/* Carino DICOM landing page — Carino workshop dark theme (gold on near-black).
   Tuned to be compact: downloads sit in the hero, tech details collapse.

   Same value-rendering policy as the dashboard (see the top of
   pacs/web/styles.css): prose wraps at spaces (word-break: normal +
   overflow-wrap: break-word), paths and URLs are the one class allowed to
   break mid-token (overflow-wrap: anywhere), and shell commands scroll inside
   their own box rather than wrap. `word-break: break-all` is never used —
   a value cut at an arbitrary character is a value read wrong. */
:root {
  --accent: #eab308;
  --bg: #050505;
  --bg-2: #0d0d0d;
  --panel: #111;
  --border: #262626;
  --text: #f5f5f5;
  --muted: #8a8a8a;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --sans: "IBM Plex Sans", system-ui, -apple-system, sans-serif;

  /* Surplus height: how much taller this viewport is than the point where the
     page stops being short of room. Measured, not guessed — the hero has 48px
     of slack at 1280×720 and 37px at 390×844, so those must not grow at all,
     while 1699×1252 wastes 571px and 1920×1080 wastes 410px.

     Every size below is written as `base + --tall × rate`, which is zero under
     900px tall and therefore leaves every short screen exactly as it was. It is
     a calc rather than a media query because a breakpoint would step: any vh
     expression steep enough to be worth having above 900px is already too steep
     below it, so switching between them jumps the whole hero at one pixel of
     resize. This form is continuous — at exactly 900px the surplus is 0px and
     both sides agree. */
  --tall: max(0px, 100vh - 900px);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* One screen: the hero takes whatever height the navbar leaves and sits its
   content at the top of it, so the page reads as composed rather than as a page
   that ran out. `min-height` and `margin` rather than a fixed 100dvh and
   `justify-content: center` — both of those clip the top of the content when it
   does not fit, and this has to degrade into an ordinary scrolling page on a
   short screen, at 200% zoom, or in a locale that runs long. */
body { margin: 0; background: var(--bg); color: var(--text); font-family: var(--sans); line-height: 1.55;
  min-height: 100dvh; display: flex; flex-direction: column; }
.hero { flex: 1 0 auto; display: flex; }
/* Anchored to the top, not centred. Centring put 288px of nothing between the
   navbar and the mark on a 1252px-tall screen, which reads as a page that has
   come loose from its own header. Surplus height now collects at the bottom,
   where it is quiet, and the hero's top padding sets the gap. */
.hero > .wrap { margin-block: 0 auto; width: min(1040px, 90%); }
a { color: var(--accent); }
.wrap { width: min(1040px, 90%); margin: 0 auto; }
.gold { color: var(--accent); }

.btn {
  display: inline-block; font-family: var(--mono); font-size: min(1.05rem, calc(.8rem + var(--tall) * .009)); letter-spacing: .04em;
  text-transform: uppercase; font-weight: 700; text-decoration: none; cursor: pointer;
  padding: min(19px, calc(9px + var(--tall) * .026)) min(32px, calc(16px + var(--tall) * .04)); border-radius: 7px; border: 1px solid var(--border); color: var(--muted);
  background: transparent; transition: .15s;
}
.btn.ghost:hover { color: var(--accent); border-color: var(--accent); }

/* ---- hero (compact, holds the downloads) ---- */
/* The whole page is this one block now, so it is sized against the viewport
   rather than against its own content: everything scales down together on a
   short screen instead of the last row falling off the bottom. The clamps are
   what make a 768px laptop and a 1080p monitor both work without a media query
   per element. Nothing is pinned to 100vh and nothing forbids scrolling — a
   reader at 200% zoom, or in a locale whose lede runs long, still gets a
   scrollbar rather than losing the bottom of the page. */
/* Leaner than it was, to pay for the EKG beside the mark. Now that the wrap is
   top-anchored this padding is also the gap under the navbar, so it does
   position something — it is the only thing holding the mark off the header,
   and it still gives ground on a short screen, which is the moment the page
   would rather spend pixels on content than on its own margins. Measured at
   1024×600, where the trim gives back what the animation takes. */
.hero { padding: min(72px, calc(clamp(12px, 2.4vh, 46px) + var(--tall) * .07)) 0 clamp(10px, 2vh, 34px); text-align: center;
  background: radial-gradient(1100px 360px at 50% -12%, rgba(234,179,8,.10), transparent 70%); }
/* The EKG above the headline. Sized off the viewport HEIGHT rather than its
   width — height is the scarce dimension on this page, so the one new block on
   it shrinks with the thing it competes against. `width: auto` + the viewBox's
   own 5:1 ratio keeps the trace undistorted at every size, and overflow stays
   visible so the pulse's glow is not clipped by the box.
   Motion is decoration here, and a reader who has asked their system for less
   of it gets the static trace: the shape carries the meaning, the sweep only
   carries the mood. */
/* Mark above the trace, the heartbeat reading as its underline. Stacked rather
   than in a row, so unlike the row version the logo does cost height — the mark
   plus the gap, which is why the gap is kept tight and only opens up on a screen
   with height to spare. The trace runs wider than the mark at every size (5:1
   against a square) and that is the point: a broad line under a compact letter,
   not two objects the same width. */
.hero-mark { display: flex; flex-direction: column; align-items: center;
  justify-content: center;
  gap: min(34px, calc(9px + var(--tall) * .05));
  margin: 0 auto min(56px, calc(clamp(3px, .7vh, 12px) + var(--tall) * .11)); }
.hero-mark .mark { width: auto; display: block;
  height: min(136px, calc(clamp(19px, 3.5vh, 44px) + var(--tall) * .21)); }
.ekg { display: block; margin: 0; width: auto; aspect-ratio: 5 / 1; overflow: visible;
  height: min(72px, calc(clamp(16px, 3vh, 38px) + var(--tall) * .10)); }
.ekg polyline { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.ekg .trace { stroke: var(--accent); stroke-width: 2; opacity: .12; }
.ekg .pulse { stroke: var(--accent); stroke-width: 2.6; stroke-dasharray: 22 120;
  filter: drop-shadow(0 0 6px rgba(234,179,8,.9)); animation: ekg 1.5s linear infinite; }
@keyframes ekg { from { stroke-dashoffset: 142; } to { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) { .ekg .pulse { animation: none; stroke-dasharray: none; } }
/* No heartbeat on a phone. It is the widest thing in the hero at 5:1, so on a
   390px screen it is either hairline-thin or it sets the width of everything
   above the fold, and a phone is the one place this page was already scrolling.
   The mark takes the space instead and grows into it — a logo reads at a glance
   where a 25px trace does not. Removed rather than hidden with visibility, so
   it gives its height back. */
@media (max-width: 640px) {
  .ekg { display: none; }
  .hero-mark .mark { height: clamp(46px, 13vw, 78px); }
}

.hero h1 { line-height: 1.1; font-weight: 800; letter-spacing: -.01em;
  font-size: min(3.6rem, calc(clamp(1.6rem, 3.6vw + .4vh, 2.7rem) + var(--tall) * .035));
  margin: 0 0 min(64px, calc(clamp(8px, 1.5vh, 16px) + var(--tall) * .11)); }
.lede { color: #d4d4d4;
  max-width: min(820px, calc(660px + var(--tall) * .35));
  font-size: min(1.32rem, calc(clamp(.92rem, .55rem + .5vh, 1.05rem) + var(--tall) * .012));
  margin: 0 auto min(52px, calc(clamp(12px, 2.4vh, 26px) + var(--tall) * .07)); }
.lede abbr { text-decoration: underline dotted var(--muted); cursor: help; }
.lede em { color: var(--text); font-style: normal; border-bottom: 1px solid var(--accent); }

/* download chips */
.downloads { display: flex; justify-content: center; flex-wrap: wrap;
  gap: min(30px, calc(14px + var(--tall) * .04)); }
.dl-btn {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: min(226px, calc(150px + var(--tall) * .09));
  padding: min(30px, calc(14px + var(--tall) * .028)) min(46px, calc(22px + var(--tall) * .04));
  border-radius: 11px; text-decoration: none;
  border: 1px solid var(--border); background: linear-gradient(180deg, var(--panel), #0a0a0a);
  color: var(--text); transition: .16s;
}
.dl-btn:hover { border-color: var(--accent); transform: translateY(-2px); }
.dl-btn b { font-size: min(1.42rem, calc(1.02rem + var(--tall) * .013)); }
.dl-btn .fmt { font-family: var(--mono); font-size: .68rem; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
/* A release carrying two architectures for one OS turns that chip from a link
   into a box with one link per arch in the format slot — a link cannot nest
   inside a link, so the chip itself stops being the hit target and the arch
   names become it. They have to look like it: the slot is 0.68rem, which is
   small enough that colour alone would not read as "press this". */
.dl-btn .fmt a { color: var(--accent); text-decoration: none; border-bottom: 1px solid rgba(234,179,8,.45); }
.dl-btn .fmt a:hover { border-bottom-color: currentColor; }
.dl-btn.recommended .fmt a { color: #3a2c00; border-bottom-color: rgba(58,44,0,.5); }
.dl-btn .rec { display: none; }
.dl-btn.recommended {
  border-color: var(--accent); background: var(--accent); color: #050505;
  box-shadow: 0 10px 30px rgba(234,179,8,.22);
}
.dl-btn.recommended .fmt { color: #3a2c00; }
.dl-btn.recommended .rec {
  display: block; position: absolute; top: -10px; left: 50%; transform: translateX(-50%);
  background: #050505; color: var(--accent); border: 1px solid var(--accent); border-radius: 999px;
  font-family: var(--mono); font-size: .56rem; letter-spacing: .1em; text-transform: uppercase; padding: 2px 8px; white-space: nowrap;
}

/* Above the buttons now, so it reads as their label rather than as a footnote.
   The number itself is gold: it is the one thing in the line worth reading, and
   the word "Version" is only there to say what the number is. */
.version { margin: 0 0 min(28px, calc(clamp(7px, 1.2vh, 14px) + var(--tall) * .035)); font-family: var(--mono); font-size: min(1rem, calc(.78rem + var(--tall) * .008)); color: var(--muted); }
.version strong { color: var(--accent); font-size: .92rem; letter-spacing: .02em; }
.version a { color: var(--accent); }
.dl-manual { margin: min(38px, calc(clamp(9px, 1.6vh, 18px) + var(--tall) * .05)) 0 0; }
.dl-all { margin: min(24px, calc(clamp(6px, 1vh, 10px) + var(--tall) * .035)) 0 0; font-size: min(1.02rem, calc(.82rem + var(--tall) * .008)); }
/* A language the manual has not been written in yet. app.js puts this on the
   manual button when it is about to hand a non-English reader the English page.
   The marker is decoration, so it lives here rather than inside the label —
   otherwise it is a translated string somebody has to remember to remove. */
.btn.soon { opacity: .62; }
.btn.soon::after { content: " · EN"; font-family: var(--mono); font-size: .72em; opacity: .8; }
.btn.soon:hover { opacity: 1; }
.dl-all a { color: var(--accent); text-decoration: none; }
.dl-all a:hover { text-decoration: underline; }

/* Server: a <button> among <a>s, so it needs the anchor resets an <a> gets for
   free, and it never takes .recommended — see the markup. */
.dl-server { font: inherit; cursor: pointer; text-align: center; }
.dl-server .fmt { text-transform: none; letter-spacing: 0; }

/* ---- modal ----
   The branding system's component (branding.carino.systems §17), built on
   <dialog> rather than a scrim div toggled with `hidden`: the element supplies
   the focus trap, Escape, the backdrop and an inert background, none of which a
   div gets for free. The anatomy and the naming are the reference's — head with
   a title and an ✕, a scrolling body — so this reads as the same component
   wherever it turns up in the fleet.

   The title is --sans, not the reference's --display: this page self-hosts no
   fonts, so Red Hat Display is not here to use. The treatment is the same. */
/* `display` only when open. The reference's .modal is a div inside a scrim that
   carries `hidden`; on a <dialog> a bare `display: flex` overrides the UA's
   `dialog:not([open]) { display: none }` and every sheet renders inline, always. */
.modal[open] { display: flex; }
.modal {
  flex-direction: column; padding: 0; overflow: hidden;
  width: min(92vw, 640px); max-height: min(88vh, 900px);
  background: var(--panel); border: 1px solid var(--border); border-radius: 14px;
  box-shadow: 0 30px 80px rgba(0,0,0,.75); color: var(--text);
}
.modal.wide { width: min(94vw, 1080px); }
.modal::backdrop { background: rgba(0,0,0,.65); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.modal-head { display: flex; align-items: center; gap: 12px; padding: 16px 18px; border-bottom: 1px solid var(--border); }
.modal-title { margin: 0; flex: 1; font-family: var(--sans); font-weight: 900; font-size: 1.05rem;
  text-transform: uppercase; letter-spacing: .5px; }
.modal-sub { margin: 0; font-family: var(--mono); font-size: .65rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: .08em; }
.modal-head form { margin: 0; }
.modal-x { border: none; background: transparent; color: var(--muted); font-size: 1.05rem; line-height: 1;
  cursor: pointer; padding: 4px 8px; border-radius: 6px; transition: .15s; }
.modal-x:hover { color: var(--accent); background: var(--accent-faint, rgba(234,179,8,.1)); }
.modal-body { padding: 18px; overflow-y: auto; }

/* ---- the row that opens them ----
   Buttons, not a bespoke pill: the reference has one button component and its
   pills are for status, not navigation. `.sm` is a size, nothing else. */
.chips { display: flex; flex-wrap: wrap; justify-content: center;
  gap: min(20px, calc(8px + var(--tall) * .03));
  margin: min(40px, calc(clamp(10px, 2vh, 18px) + var(--tall) * .055)) auto 0; max-width: min(980px, 94vw); }
.btn.sm { padding: min(15px, calc(6px + var(--tall) * .024)) min(26px, calc(13px + var(--tall) * .035)); font-size: min(.92rem, calc(.7rem + var(--tall) * .008)); letter-spacing: .06em; }
.btn.sm:hover { color: var(--accent); border-color: var(--accent); background: rgba(234,179,8,.08); }

/* A phone has the same content and a third of the height, and the download
   buttons are the biggest thing on it — four of them wrap to two rows. Trimming
   their padding and the gaps around them is what keeps the chip row on screen
   instead of half a row below it. */
/* Short screens, any width. Russian runs about a line longer than English
   everywhere it appears, which is enough to push a 1366x768 laptop over by
   itself — so the trim is keyed to the height that is short rather than to the
   language that is long. */
@media (max-height: 780px) {
  /* Font size only — narrowing max-width here would wrap the text to MORE lines
     and make the block taller, which is the opposite of the point. */
  .lede { font-size: .95rem; max-width: 720px; }
  .dl-note { font-size: .78rem; max-width: 640px; }
}

@media (max-width: 560px) {
  .dl-btn { min-width: 118px; padding: 9px 14px; gap: 0; }
  .dl-btn b { font-size: .95rem; }
  .downloads { gap: 8px; }
  .lede { font-size: .88rem; }
  .dl-note { font-size: .76rem; }
  .chips { gap: 6px; }
  .chip { padding: 4px 10px; font-size: .72rem; }
  .btn.ghost { padding: 7px 13px; }
}
/* Stacked, not three columns. The commands are the reason the dialog exists and
   they scroll rather than wrap — a wrapped shell line is a line somebody pastes
   wrong — so each one needs the full width to be readable at all. Side by side,
   every command was cut off at its first argument. */
.server-opts { display: grid; gap: 18px; text-align: left; }
.server-opts article { display: grid; grid-template-columns: minmax(0, 200px) minmax(0, 1fr); gap: 6px 20px; align-items: start; }
.server-opts h3 { margin: 0; font-size: 1rem; grid-column: 1; }
.server-opts p { margin: 0; color: var(--muted); font-size: .84rem; grid-column: 1; }
/* The commands are the one place a horizontal scrollbar is the right answer:
   a wrapped shell command is a command someone will paste wrong. */
.server-opts pre { margin: 0; overflow-x: auto; grid-column: 2; grid-row: 1 / span 3;
  background: #000; border: 1px solid var(--border); border-radius: 10px; padding: 13px; }
.server-opts pre code { font-family: var(--mono); font-size: .76rem; line-height: 1.65;
  color: #e8e8e8; white-space: pre; }
.server-opts a { color: var(--accent); text-decoration: none; font-size: .82rem; grid-column: 1; }
.server-opts a:hover { text-decoration: underline; }
@media (max-width: 640px) {
  .server-opts article { grid-template-columns: 1fr; }
  .server-opts pre { grid-column: 1; grid-row: auto; }
}
.server-foot { margin: 18px 0 0; font-size: .84rem; }
.server-foot a { color: var(--accent); text-decoration: none; }
.server-foot a:hover { text-decoration: underline; }

/* The download chips used to be the only way in; Docker and systemd are now
   first-class, so the hero says so before the visitor scrolls past them. */
.dl-note { max-width: min(720px, calc(560px + var(--tall) * .35));
  margin: min(26px, calc(8px + var(--tall) * .04)) auto 0;
  font-size: min(1.02rem, calc(.82rem + var(--tall) * .008)); color: var(--muted);
  word-break: normal; overflow-wrap: break-word; }

/* The note used to say the newest installer was a release behind the page, and
   it is tinted because that was the only thing standing between a visitor and a
   download that did not match what they had just read. The installers have
   caught up; what the note carries now is the architecture split, which is the
   same kind of fact — something a visitor has to read BEFORE clicking, because
   an Intel Mac handed an Apple Silicon build does not open it. So the tint
   stays. */
.release-note { border-left: 2px solid var(--accent); padding-left: 12px; text-align: left; }
.release-note b { color: var(--accent); }
.release-note a { white-space: nowrap; }
.release-note code { word-break: normal; overflow-wrap: anywhere; }

.firstrun { max-width: 560px; margin: 16px auto 0; text-align: left; }
.firstrun summary { cursor: pointer; text-align: center; font-size: .82rem; color: var(--muted); padding: 8px 0; }
.firstrun summary:hover { color: var(--accent); }
.firstrun ul { margin: 6px 0; padding-left: 20px; color: #cfcfcf; font-size: .9rem; }
.firstrun p { color: var(--muted); font-size: .82rem; margin: 4px 0 0; }
/* Inline code in prose is an identifier or a path — the one value class allowed
   to break mid-token, because `pacs serve|receive|send|…` and
   `/Applications/Carino-DICOM.app` carry no spaces to break at and would
   otherwise push the whole page sideways on a phone. Block code inside <pre>
   is exempt below: it scrolls in its own box instead. */
.firstrun code, .techbox code, .tech-body code { font-family: var(--mono); background: #000; padding: 1px 5px; border-radius: 4px; overflow-wrap: anywhere; }

/* ---- compact content section ---- */
.section { padding: 40px 0; }
.section.alt { background: linear-gradient(180deg, var(--bg-2), var(--bg)); border-top: 1px solid var(--border); }
.section h2 { font-size: 1.3rem; margin: 0 0 14px; }
.section h2.center { text-align: center; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; }
@media (max-width: 760px) { .grid2 { grid-template-columns: 1fr; gap: 26px; } }

/* Section standfirst. Prose, so it wraps at spaces: word-break stays normal and
   overflow-wrap only cuts a word that cannot fit a line on its own. */
.sub { max-width: 640px; margin: -6px auto 22px; text-align: center; color: var(--muted);
  font-size: .9rem; word-break: normal; overflow-wrap: break-word; }
.sub.left { margin-left: 0; margin-right: 0; text-align: left; }


/* The manuals are a centred strip rather than a section with a heading and a
   standfirst — three buttons did not need three paragraphs around them. */

/* ---- what it does ---- */
.svc { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); gap: 18px; }
.svc-item { background: linear-gradient(180deg, var(--panel), #0a0a0a); border: 1px solid var(--border);
  border-radius: 11px; padding: 15px 17px; min-width: 0; }
.svc-item b { display: block; margin-bottom: 5px; font-size: .95rem; color: var(--text);
  word-break: normal; overflow-wrap: break-word; }
/* Which release a capability ships in, on the capability itself. This is what
   replaced a second list that repeated every card underneath a "Coming in
   v1.1.0" heading — the version belongs to the feature, not to a section. */
.svc-ver {
  display: inline-block; margin-bottom: 7px; padding: 1px 7px; border-radius: 999px;
  font-family: var(--mono); font-size: .62rem; letter-spacing: .05em;
  border: 1px solid var(--border); color: var(--muted); white-space: nowrap;
}
.svc-ver.now { border-color: var(--accent); color: var(--accent); }
.svc-item p { margin: 0; font-size: .84rem; line-height: 1.5; color: #b0b0b0;
  word-break: normal; overflow-wrap: break-word; hyphens: auto; }

/* ---- what it is / what it is not, paired ----
   Two columns that collapse to one, and they collapse in the right order:
   "what it is" first, because a visitor who reads only the red box has been
   told what this cannot do without ever being told what it can. */
.contrast { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; align-items: start; }
@media (max-width: 860px) { .contrast { grid-template-columns: 1fr; gap: 18px; } }
.isbox {
  border: 1px solid var(--border); border-left: 4px solid var(--accent);
  border-radius: 12px; padding: 20px 22px; background: rgba(234, 179, 8, .05);
  min-width: 0;
}
.isbox h2 { margin: 0 0 12px; color: var(--accent); }
.isbox ul { list-style: none; margin: 0; padding: 0; }
.isbox li { margin-bottom: 11px; font-size: .88rem; line-height: 1.55; color: #d4d4d4;
  word-break: normal; overflow-wrap: break-word; }
.isbox li b { color: var(--text); }

/* ---- what it is NOT ----
   Deliberately a panel and not a footnote: a reader who skims the page still
   has to walk past this, because "not a medical device" set in fine print is
   the kind of thing that gets discovered after a deployment, not before. */
.notbox { border: 1px solid #7f1d1d; border-left: 4px solid #b91c1c;
  border-radius: 12px; padding: 20px 22px; background: rgba(185, 28, 28, .06); min-width: 0; }
.notbox h2 { margin: 0 0 12px; color: #f87171; }
.notbox ul { list-style: none; margin: 0; padding: 0; }
.notbox li { margin-bottom: 11px; font-size: .88rem; line-height: 1.55; color: #d4d4d4;
  word-break: normal; overflow-wrap: break-word; }
.notbox li b { color: #fca5a5; }
.notbox-foot { margin: 14px 0 0; font-size: .84rem; color: var(--muted);
  word-break: normal; overflow-wrap: break-word; }



/* ---- tech (collapsed by default) ---- */
.techbox { max-width: 860px; margin: 0 auto; }
.techbox > summary { cursor: pointer; font-size: 1.02rem; padding: 6px 0; }
.techbox > summary:hover { color: var(--accent); }
.techbox > summary b { color: var(--text); }
.tech-body { padding-top: 12px; color: #cfcfcf; }
.tech-list { padding-left: 20px; }
/* PROSE, and it was the one list in this file that never said so. Left on the
   defaults it overflowed its own box by 5-10px at 320px in Spanish and
   Portuguese — "QIDO-RS, WADO-RS, STOW-RS" alongside a translated clause has no
   break point narrow enough, and `overflow-wrap: normal` will not make one.
   break-word only breaks a word that cannot fit a line on its own, which is
   exactly the case here and nowhere else in the list. */
.tech-list li { margin-bottom: 7px; word-break: normal; overflow-wrap: break-word; }
.tech-body pre { background: #000; border: 1px solid var(--border); border-radius: 10px; padding: 14px; overflow-x: auto; }
.tech-body pre code { background: none; padding: 0; font-size: .8rem; line-height: 1.7; color: #e8e8e8;
  white-space: pre; overflow-wrap: normal; }
.tech-links { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 16px; }

