/* ---------------------------------------------------------------------- *
 * Shared chrome for every public MELD page.
 *
 * One nav, one footer, one set of tokens. Linked by /master/, /myroc,
 * /mystudio, / and the legal pages so a visitor can move between products
 * without going back to the front door. Deliberately NOT loaded by the hub:
 * Mission Control is internal and has no business advertising the products.
 * ---------------------------------------------------------------------- */

/* ------------------------------------------------------------------ *
 * THE hidden ATTRIBUTE ACTUALLY HIDES THINGS
 *
 * `hidden` is only `display: none` from the browser's own stylesheet, so ANY
 * author rule that sets display beats it. An element with `hidden` and a class
 * that says `display: grid` is visible, silently, and the code that set the
 * attribute looks correct.
 *
 * This is not hypothetical. The account page set `hidden` on the sign-in form
 * once somebody was signed in, and `.ac-signin { display: grid }` overrode it -
 * so a signed-in person scrolled past their own dashboard and was asked to
 * sign in again. Three panels on /master/ had the same fault. The hub's
 * stylesheet had already grown eight separate one-off `[hidden]{display:none}`
 * patches, each added the day somebody noticed.
 *
 * So it is stated once, here, for the whole site. !important is right: the
 * attribute is a statement that the element is not part of the page, and
 * nothing about how a thing looks should be able to argue with whether it is
 * there at all. Toggle visibility with el.hidden and it will work.
 * ------------------------------------------------------------------ */
[hidden] { display: none !important; }

:root {
  /* ======================== THE CONSOLE PALETTE ========================= *
   *
   * Warm graphite rather than flat black; an amber that only ever means
   * "signal"; square corners because hardware has square corners.
   *
   * The old palette was #1c1a17 and a cyan accent. It read as a website
   * about music. This one reads as the faceplate of something you record
   * onto, which is the whole point of the overhaul.
   *
   * Every value below was contrast-checked against --bg before it went in.
   * Two of them had to move away from the approved renders to get there,
   * and the reasons are on the lines themselves. */

  --bg: #1c1a17;          /* warm graphite, 13.6:1 under --txt */
  --panel: #14120f;       /* recessed: panels sit DARKER than the page */
  --panel-2: #241f1a;     /* raised: the face of a control */
  --line: #2e2a24;        /* the seam between panels */
  --line-2: #3a342c;      /* a lit edge, or a hovered border */
  --txt: #e8e3d9;         /* 13.58:1 */
  --txt-bright: #f4efe4;  /* 15.14:1 - headings and live numbers */
  --field: #1c1a17;       /* the inside of an input, darker than any panel */

  /* THESE TWO CARRY REAL TEXT, so they are not the render's values.
     The approved comp used #b3a89a / #8f8579 for these greys. #8f8579 is
     3.12:1 - it FAILS WCAG AA for normal text, and on this site --faint is
     not decorative: it carries the inactive nav tabs, the footer links and
     the copyright line. A design that is unreadable for anyone with less
     than perfect eyesight is not the design we approved, it is a picture of
     it. Both moved up until they cleared 4.5:1, keeping a 1.66x luminance
     gap so they still read as two distinct greys. */
  --muted: #b3a89a;       /* 7.43:1 - secondary prose */
  --faint: #8f8579;       /* 4.79:1 - labels, nav, footer */

  /* The VU lamp. Amber means signal: a live meter, the active nav tab, the
     primary action. It is never decoration. */
  --accent: #e8a33d;
  --accent-hot: #f5bd63;  /* hover only */
  --accent-ink: #1c1a17;  /* text ON amber - 8.05:1 the other way round */

  --ok: #5da271;          /* 5.68:1 - within target, ready, connected */
  /* THE RED COMES IN TWO, AND THIS NOTE USED TO SAY SO.
   *
   * The artboard red is #c4553d. Against the panel ground it measures 3.90:1
   * and against the darkest ground 4.20:1 - both below the 4.5:1 that text
   * has to clear. So it is the colour of a FILL: a meter, a border, a dot,
   * the armed state of a button.
   *
   * Text needs its own, and #d17a68 is that red lightened 22% - the same hue
   * to within a few degrees, 5.96:1 on the darkest ground and 4.55:1 on the
   * lightest one the console uses.
   *
   * Collapsing the two is how #d4694f (4.91:1, and in none of the seventeen
   * artboards) got into sixty-four places: somebody needed readable red and
   * the only red token was the unreadable one. */
  --warn: #c4553d;        /* fills, borders, meters - never running text */
  --warn-txt: #d17a68;    /* red TEXT, and the only red that clears AA */
  --info: #6f9fc4;        /* 6.14:1 */

  /* ---------------------------- typography ---------------------------- *
   * Three faces, each with one job. Served from /fonts.css, self-hosted.
   *   display - condensed, for faceplate lettering and headlines
   *   sans    - prose
   *   mono    - anything that is a NUMBER, so digits do not dance when a
   *             meter moves, plus the small uppercase channel labels */
  --font-display: 'Barlow Condensed', 'Arial Narrow', system-ui, sans-serif;
  --font-sans: 'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, Menlo, Consolas, monospace;

  /* The small uppercase mono label used above every panel. One definition,
     because there are about forty of them across the site. */
  --label-size: .72rem;
  --label-tracking: .14em;

  /* One page width for the whole public site. Fluid: it grows with the window
     up to a ceiling and shrinks below it, so there is no width at which the
     layout stops responding. Every page reads this rather than hard-coding
     its own number, which is how /master and /mystudio ended up disagreeing. */
  --meld-page: min(1600px, 94vw);

  /* ------------------------------ buttons ------------------------------ *
   *
   * One shape for every call to action on the public site. A crawl of eleven
   * pages once found ELEVEN distinct button styles across twenty-one
   * controls; these tokens are the single definition. Page-local rules set
   * colour, width and layout; they do not set size, weight, padding, radius
   * or tracking.
   *
   * Square now (2px, not 9px) and uppercase: this is a console, and the
   * buttons on a console are rectangles. */
  --btn-size: .82rem;
  --btn-weight: 600;
  --btn-pad-y: .85rem;
  --btn-pad-x: 1.7rem;
  --btn-radius: 2px;
  --btn-tracking: .09em;
  --btn-transition: transform .15s ease, background .15s ease,
                    border-color .15s ease, color .15s ease;

  /* Square corners everywhere else too. Kept as a token so a page that wants
     a soft edge has to say so on purpose. */
  --radius: 2px;
  --radius-panel: 3px;
}


/* The canonical control. Works as <a> or <button>. */
.meld-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  font: inherit; font-size: var(--btn-size); font-weight: var(--btn-weight);
  letter-spacing: var(--btn-tracking); text-transform: none; text-decoration: none;
  padding: var(--btn-pad-y) var(--btn-pad-x);
  border-radius: var(--btn-radius); border: 1px solid var(--line-2);
  /* A DEFAULT SKIN, not a transparent one. .meld-btn had no background of its
     own, so a button written without .primary or .ghost - and the Studio has
     several, "Record something" among them - fell through to the browser's
     own buttonface and rendered as a WHITE box in the middle of a dark
     recording tool. Transparent borders hid the same problem on the edges. */
  background: var(--panel-2); color: var(--txt);
  cursor: pointer; transition: var(--btn-transition);
}
.meld-btn:hover { border-color: var(--accent); color: var(--accent); }
.meld-btn.primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.meld-btn.primary:hover { background: var(--accent-hot); border-color: var(--accent-hot); color: var(--accent-ink); transform: translateY(-1px); }
.meld-btn.ghost { background: transparent; border-color: var(--line); color: var(--txt); }
.meld-btn.ghost:hover { border-color: var(--accent); color: var(--accent); }
.meld-btn:disabled, .meld-btn[aria-disabled="true"] {
  opacity: .5; cursor: not-allowed; transform: none;
}
/* Every control gets the same visible focus ring. Several of these had none,
   which makes the site unusable by keyboard without guessing where you are. */
.meld-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .meld-btn, .meld-btn:hover { transition: none; transform: none; }
}

/* ------------------------------ typography ---------------------------- *
 *
 * The public pages declared no font at all, so they rendered in whatever the
 * browser defaults to - while /master and the hub asked for Inter. The site
 * therefore changed typeface when you walked from the home page into the
 * mastering tool, which is exactly the kind of seam this stylesheet exists to
 * remove.
 *
 * Declared HERE because this is the only stylesheet every page loads. home.css
 * looked like the right home for it until /jam and the legal pages turned out
 * not to load home.css at all - and the two files load in a different order on
 * different pages, so a rule in both would resolve differently by page. There
 * is one declaration, and it is this one.
 *
 * Inter is NAMED but NOT FETCHED. Anyone who has it gets it; everyone else
 * gets the system UI face, which is what the public pages were already using
 * and is a perfectly good one. That is a deliberate trade: loading it from
 * Google Fonts would put a request to Google on every page of a site whose
 * pitch is that nothing leaves your machine, and the privacy page does not
 * disclose Google Fonts - only their STUN servers. A typeface is not worth
 * making that page wrong.
 */
body {
  font-family: var(--font-sans);
}

/* ------------------------------------------------------------------ *
 * AUTOFILL MUST NOT REPAINT THE FORM WHITE.
 *
 * Chrome paints a filled field with its own pale blue - rgb(232,240,254) - and
 * black text, through an internal pseudo-class. It overrides `background`, so
 * the sign-in card looked correct until a password manager filled it and then
 * had two glaring white boxes in the middle of a dark panel. That is what the
 * hub login was doing: the page CSS was right, the browser was painting over
 * it.
 *
 * background-color cannot win. An INSET box-shadow can - it is drawn over the
 * background, respects the border radius, and Chrome does not override it. The
 * absurd transition delay is the other half: Chrome re-applies its colour
 * after a transition completes, and one that takes a day never completes.
 * ------------------------------------------------------------------ */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active,
textarea:-webkit-autofill,
select:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 100vmax var(--field) inset;
          box-shadow: 0 0 0 100vmax var(--field) inset;
  -webkit-text-fill-color: var(--txt);
  caret-color: var(--txt);
  transition: background-color 100000s ease-in-out 0s;
}

/* ------------------------------- nav --------------------------------- */

.meld-nav {
  position: sticky; top: 0; z-index: 90;
  background: rgba(20,18,15,.86);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--line);
}
/* A page that makes <body> a centring flex column - myroc.html does, to centre
   its jam card - turns this bar into a flex item, and `align-items: center`
   shrink-wraps a flex item to its content. The bar became 426px inside a 390px
   phone and scrolled the entire document sideways. Stated here rather than
   patched in myroc.html so the next page to centre its body cannot repeat it. */
.meld-nav { width: 100%; align-self: stretch; max-width: 100%; }

.meld-nav-inner {
  /* Was a hardcoded 1040px, which left the nav visibly narrower than the page
     under it once the shell grew. */
  width: var(--meld-page); max-width: 100%; margin: 0 auto;
  padding: 0 1.5rem;
  display: flex; align-items: center; gap: .35rem;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.meld-nav-inner::-webkit-scrollbar { display: none; }

.meld-nav a {
  flex: 0 0 auto;
  padding: .95rem .85rem;
  /* Stated, not inherited. Everything else here is in rem, so the bar should
     have been the same height everywhere - but line-height is inherited from
     body, and /master sets 15px type while the legal pages set their own. The
     bar came out 47px on Master, 52px on most pages and 53px on the legal
     ones, so it visibly jumped as you moved between them. */
  line-height: 1.5;
  font-size: .74rem; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--faint); text-decoration: none;
  border-bottom: 2px solid transparent;
  transition: color .15s ease, border-color .15s ease;
  white-space: nowrap;
}
.meld-nav a:hover { color: var(--txt); }
.meld-nav a.is-active { color: var(--accent); border-bottom-color: var(--accent); }

/* The first item is the wordmark, so it carries more weight than the tabs.
   Scoped to a direct child of the bar: the tabs now sit inside a wrapper, and
   `.meld-nav a:first-child` matched the first tab in that wrapper too, giving
   Master the wordmark's weight and letter-spacing. */
.meld-nav-inner > a:first-child {
  color: var(--txt); letter-spacing: .2em; font-weight: 800;
  padding-left: 0; margin-right: .6rem;
}
.meld-nav-inner > a:first-child.is-active { color: var(--accent); }

/* ------------------------- nav: tabs and account ---------------------- *
 *
 * Seven items do not fit a 360px phone - five already needed 360px exactly.
 * The bar has always scrolled sideways instead of overflowing the document,
 * which is safe but hides links behind a gesture nobody knows is there.
 *
 * So below 600px the tabs collapse behind a Menu button. The wordmark and the
 * account link stay visible, because "where am I" and "sign in" are the two
 * things worth a permanent tap target.
 *
 * The collapse is keyed on [data-collapsible="on"], which meld-chrome.js sets
 * once it has unhidden the button. Without scripting the attribute is never
 * set, the button stays hidden, and every tab stays on screen in the scrolling
 * bar - degraded, but nothing is unreachable. */

.meld-nav-links { display: flex; align-items: center; gap: .35rem; min-width: 0; }

/* Pushed to the far right, and kept there on every viewport. */
/* The auto margin lives HERE and only here. Every one of the fifteen pages
   with the nav has this link, so it is always present to do the pushing - and
   the bell, appended after it, is carried to the right edge with it. Giving
   the bell an auto margin of its own put a second gap between the two and
   stranded the bell in the middle of the bar. */
.meld-nav-account { margin-left: auto; flex: 0 0 auto; color: var(--txt); }
/* When the rail hides that link it leaves the flex row, taking the auto margin
   with it - and the bell drifts back toward the middle. The bell takes over the
   pushing in exactly that case. */
.meld-nav-inner:has(.meld-nav-account[hidden]) .meld-bell { margin-left: auto; }
.meld-nav-account:hover { color: var(--accent); }

.meld-nav-toggle {
  display: none;
  flex: 0 0 auto;
  padding: .95rem .85rem;
  line-height: 1.5;
  font: inherit;
  font-size: .74rem; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--faint); background: none; border: 0;
  border-bottom: 2px solid transparent;
  cursor: pointer; white-space: nowrap;
}
.meld-nav-toggle:hover { color: var(--txt); }
.meld-nav-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.meld-nav-toggle[aria-expanded="true"] { color: var(--accent); }

@media (max-width: 599px) {
  .meld-nav[data-collapsible="on"] .meld-nav-toggle { display: inline-block; }

  /* Out of the bar and into a panel beneath it. Laid out as a column so the
     tap targets are full width rather than five small ones in a row. */
  .meld-nav[data-collapsible="on"] .meld-nav-links {
    display: none;
    position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    padding: .25rem 1.5rem .75rem;
    background: rgba(20,18,15,.97);
    border-bottom: 1px solid var(--line);
  }
  .meld-nav[data-collapsible="on"][data-open="true"] .meld-nav-links { display: flex; }
  .meld-nav[data-collapsible="on"] .meld-nav-links a {
    padding: .8rem 0;
    border-bottom: 1px solid var(--line);
  }
  .meld-nav[data-collapsible="on"] .meld-nav-links a:last-child { border-bottom: 0; }
  .meld-nav[data-collapsible="on"] .meld-nav-links a.is-active {
    color: var(--accent); border-bottom-color: var(--line);
  }

  /* The panel is positioned against the bar, so the bar must be the containing
     block - and it must not clip the panel it is trying to show. */
  .meld-nav[data-collapsible="on"] { position: sticky; }
  .meld-nav[data-collapsible="on"] .meld-nav-inner { position: static; overflow-x: visible; }
}

/* ------------------------------ footer ------------------------------- *
 *
 * Pinned to the bottom of the window, with the nav pinned to the top, so only
 * the content between them scrolls.
 *
 * The catch, and why the footer is one compact row rather than the three
 * stacked ones it used to be: every pixel a fixed bar occupies is a pixel the
 * page never gets back. A nav plus a tall footer on a phone can eat a third of
 * the screen, and MYROC's card is already tall. So the bar is deliberately
 * short, and on genuinely small viewports it returns to normal flow rather
 * than squeezing the thing you came to use.
 */

.meld-foot {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 90;
  /* Stated explicitly, and not left to inherit. home.css styles the bare
     `footer` element for its own layout, and that rule also matches this one -
     which made the bar 83px taller on every page that loads home.css. */
  padding: 0; margin: 0; font-size: 1rem;
  border-top: 1px solid var(--line);
  background: rgba(20,18,15,.88);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  backdrop-filter: saturate(140%) blur(10px);
}
.meld-foot-inner {
  /* Same shell width as the nav and the page, so the three line up. */
  width: var(--meld-page); max-width: 100%; margin: 0 auto;
  padding: .55rem 1.5rem;
  display: flex; align-items: center; justify-content: space-between;
  gap: .75rem 1.4rem; flex-wrap: wrap;
}

/* Content must not end underneath the bar. The value tracks the bar's real
   height; if the footer grows, this grows with it. */
body { padding-bottom: var(--foot-h, 4.25rem); }

.meld-foot .icons { display: flex; gap: .9rem; }
.meld-foot .icons a {
  color: var(--txt); opacity: .66;
  display: inline-flex; padding: .25rem;
  transition: opacity .15s ease, color .15s ease, transform .15s ease;
}
.meld-foot .icons a:hover { opacity: 1; color: var(--accent); transform: translateY(-2px); }
.meld-foot .icons svg { width: 19px; height: 19px; display: block; }

.meld-foot-links {
  margin: 0; display: flex; flex-wrap: wrap; gap: .3rem 1.1rem;
  font-size: .74rem;
}
.meld-foot-links a { color: var(--faint); text-decoration: none; white-space: nowrap; }
.meld-foot-links a:hover { color: var(--accent); }
.meld-foot-note { margin: 0; color: var(--faint); font-size: .7rem; white-space: nowrap; }

/* Narrow screens: drop the copyright line before anything useful goes. */
/* All four tabs fit a phone rather than scrolling out of reach.
   The bar scrolls horizontally as a fallback, but a visitor cannot see that it
   scrolls - so on a 390px screen the page they are ON had its own tab off the
   right edge, which reads as a missing product, not a hidden one. Tightening
   the padding and letter-spacing fits the full set with room to spare. */
@media (max-width: 460px) {
  /* Retightened when a fifth tab was added. Measured, not guessed: with the
     previous values the five tabs needed 401px, so on a 360px phone - an
     extremely common Android width - the last one sat off the right edge. These
     values bring the row inside 360. */
  .meld-nav-inner { padding: 0 .45rem; gap: 0; }
  .meld-nav a { padding: .95rem .34rem; letter-spacing: .05em; font-size: .7rem; }
  .meld-nav-inner > a:first-child { margin-right: .15rem; letter-spacing: .1em; }
}

@media (max-width: 620px) {
  .meld-foot-inner { justify-content: center; padding: .5rem 1rem; }
  .meld-foot-note { display: none; }
  body { padding-bottom: var(--foot-h, 5.5rem); }
}

/* Genuinely tiny viewports only - a phone held in landscape.
 *
 * This was 620px, which sounds small and is not: an iPhone in PORTRAIT, once
 * Safari's address bar and toolbar are subtracted, is around 530px of usable
 * height. The rule was therefore un-pinning the footer on the most common
 * device there is, which is exactly the bug it was written to avoid causing.
 * 430px is a landscape phone and nothing else.
 */
@media (max-height: 430px) {
  .meld-foot { position: static; -webkit-backdrop-filter: none;
 backdrop-filter: none; background: var(--bg); }
  body { padding-bottom: 0; }
}

/* Someone who has asked for less motion should not get a blurred, translucent
   bar sliding under their content either. */
@media (prefers-reduced-transparency: reduce) {
  .meld-nav, .meld-foot { -webkit-backdrop-filter: none;
 backdrop-filter: none; background: var(--bg); }
}

/* ------------------------------ the wall ------------------------------- *
 *
 * Shown when someone has used an allowance. Styled once here so the moment
 * looks the same in Studio, Master, Jam and Social - a visitor meeting it in
 * two products should not think two different things went wrong.
 *
 * Deliberately not alarming. It is not an error: they used something up, and
 * the next step is free. Accent border, not red.
 */
.meld-wall {
  margin: 1.1rem 0;
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--accent);
  border-radius: 3px;
  background: rgba(232, 163, 61, .06);
}
.meld-wall h3 {
  margin: 0 0 .45rem;
  font-size: 1rem; font-weight: 700; color: var(--txt);
}
.meld-wall p {
  margin: 0 0 .9rem;
  font-size: .9rem; line-height: 1.55; color: var(--muted);
}
.meld-wall-cta {
  display: inline-block;
  padding: .6rem 1.1rem;
  border-radius: 999px;
  background: var(--accent); color: #14120f;
  font-size: .82rem; font-weight: 700; letter-spacing: .04em;
  text-decoration: none;
}
.meld-wall-cta:hover { background: #f5bd63; }
.meld-wall-cta:focus-visible { outline: 2px solid var(--txt); outline-offset: 2px; }


/* ------------------------- fields on a phone --------------------------- *
 *
 * iOS Safari zooms the page in whenever a focused field's text is smaller than
 * 16px, and then leaves it zoomed - so tapping the email box on the sign-in
 * page threw the whole layout sideways on an iPhone. The site's fields are
 * .95rem, which is 15.2px.
 *
 * Fixed at the size where it matters rather than everywhere, so the desktop
 * proportions are unchanged. 16px exactly: the zoom threshold is what this is
 * about, not a design decision.
 */
@media (max-width: 640px) {
  /* !important, deliberately, and it is the only one in this file.
   *
   * THIS RULE WAS ALREADY HERE AND IT WAS LOSING. Every page that styles its
   * own fields does so with a class - .mg-gif-search input, .fd-form input,
   * .ac input - and a class beats a bare element selector on specificity, so
   * six controls quietly went back under the threshold. One of them was the
   * GIF search, which focuses ITSELF when the tab opens: Safari zoomed the
   * page, and because it does not zoom back out on blur, the sheet stayed
   * hanging off the right edge of the screen long after. From the outside it
   * looked like a broken layout, not a font size.
   *
   * "no control is ever under 16px on a phone" is not a preference another
   * stylesheet should be able to outvote by being more specific, and there is
   * no design that wants it. So it wins outright, inside this media query
   * only, and a test fails if anything drops below it again. */
  input, select, textarea { font-size: 16px !important; }
}

/* ------------------------- the guided walkthrough ---------------------- *
 *
 * A card beside the thing it is describing, and a ring around that thing.
 * Deliberately NOT a modal over a dimmed page: somebody who wants to stop
 * reading and just use the site can, and the ring is pointer-events:none so it
 * can never swallow the click the step is asking for.
 */
.meld-tour-ring {
  /* Above the page and above the sticky bars (90), below 100 - the site keeps
     everything under 100 so a real dialog can always sit over it. */
  position: absolute; z-index: 95;
  border: 2px solid var(--accent); border-radius: 3px;
  box-shadow: 0 0 0 4px rgba(232,163,61,.14);
  pointer-events: none;
}
.meld-tour {
  position: absolute; z-index: 96;
  width: min(22rem, calc(100vw - 1rem));
  padding: 1rem 1.1rem;
  background: var(--panel);
  border: 1px solid var(--accent); border-radius: 3px;
  box-shadow: 0 12px 40px rgba(0,0,0,.5);
}
.meld-tour-count {
  margin: 0 0 .35rem;
  font-size: .68rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent);
}
.meld-tour h2 { margin: 0 0 .4rem; font-size: 1.02rem; font-weight: 700; color: var(--txt); }
.meld-tour-body { margin: 0; font-size: .9rem; line-height: 1.55; color: var(--muted); }
.meld-tour-row { display: flex; gap: .5rem; align-items: center; margin-top: .9rem; }
.meld-tour-skip {
  font: inherit; font-size: .8rem; color: var(--faint);
  background: none; border: 0; padding: .4rem .2rem; cursor: pointer;
}
.meld-tour-skip:hover { color: var(--txt); }
.meld-tour-next {
  margin-left: auto;
  font: inherit; font-size: .82rem; font-weight: 700;
  padding: .5rem 1rem; border-radius: 999px; border: 0; cursor: pointer;
  background: var(--accent); color: #14120f;
}
.meld-tour-next:hover { background: #f5bd63; }
.meld-tour-skip:focus-visible, .meld-tour-next:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .meld-tour, .meld-tour-ring { transition: none; }
}

/* The optional second way forward - "Skip the jam" and anything like it.
   Quieter than Next, louder than Skip: it moves you on rather than out. */
.meld-tour-alt {
  margin-left: auto;
  font: inherit; font-size: .8rem; font-weight: 600;
  padding: .5rem .8rem; border-radius: 999px; cursor: pointer;
  background: none; color: var(--muted);
  border: 1px solid var(--line);
}
.meld-tour-alt:hover { color: var(--txt); border-color: var(--muted); }
.meld-tour-alt:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* With an alt present, Next stops being the only thing pushed right. */
.meld-tour-alt + .meld-tour-next { margin-left: .5rem; }

/* ------------------------------------------------------------------ *
 * TOASTS
 *
 * Bottom-right on a desktop, across the bottom on a phone. Above everything
 * except a modal, and never over the nav: a notification that covers the way
 * out is worse than one you missed.
 * ------------------------------------------------------------------ */
.meld-toasts {
  /* 95: above the sticky nav at 90, so a toast is never tucked behind the bar,
     and below 100 so it can never cover a dialog. Nothing in the shared chrome
     is allowed past 100 - a notification that hides the way out of a modal is
     worse than one you missed. */
  position: fixed; right: 1rem; bottom: 1rem; z-index: 95;
  display: flex; flex-direction: column-reverse; gap: .6rem;
  width: min(22rem, calc(100vw - 2rem)); pointer-events: none;
}
.meld-toast {
  position: relative; pointer-events: auto;
  background: var(--panel); border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: 3px; padding: .85rem 2.2rem .85rem 1rem;
  box-shadow: 0 18px 42px rgba(0, 0, 0, .55);
  animation: meld-toast-in .18s ease-out;
}
@keyframes meld-toast-in { from { opacity: 0; transform: translateY(8px); } }

/* ------------------------------------------------------------------ *
 * ON A PHONE A TOAST COMES FROM THE TOP
 *
 * Bottom-right is right on a desktop, where the corner is empty. On a phone
 * the bottom of the screen is the composer, the tab bar, and - once you are
 * typing - the keyboard. A notification landing there covers the exact
 * control you are using, which is how a message about a message ends up
 * blocking the reply to it.
 *
 * Top, under the nav, where there is nothing to cover.
 * ------------------------------------------------------------------ */
@media (max-width: 720px) {
  .meld-toasts {
    right: .6rem; left: .6rem; width: auto;
    bottom: auto; top: calc(var(--meld-nav-h, 56px) + .6rem);
    flex-direction: column;
  }
  .meld-toast { animation-name: meld-toast-drop; }
}
@keyframes meld-toast-drop { from { opacity: 0; transform: translateY(-8px); } }
@media (prefers-reduced-motion: reduce) { .meld-toast { animation: none; } }
.meld-toast-title { margin: 0; font-size: .9rem; font-weight: 600; overflow-wrap: anywhere; }
.meld-toast-body { margin: .3rem 0 0; font-size: .82rem; color: var(--muted); line-height: 1.5; }
.meld-toast-actions { display: flex; gap: .45rem; flex-wrap: wrap; margin: .7rem 0 0; }
.meld-toast-btn {
  font: inherit; font-size: .8rem; padding: .35rem .75rem; border-radius: 3px;
  border: 1px solid var(--line); background: transparent; color: var(--muted);
  cursor: pointer; text-decoration: none; transition: var(--btn-transition);
}
.meld-toast-btn:hover { border-color: var(--accent); color: var(--accent); }
.meld-toast-btn.primary { background: var(--accent); border-color: var(--accent); color: #241f1a; font-weight: 600; }
.meld-toast-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.meld-toast-x {
  position: absolute; top: .45rem; right: .5rem; width: 1.5rem; height: 1.5rem;
  display: grid; place-items: center; font-size: 1.1rem; line-height: 1;
  background: transparent; border: 0; color: var(--faint); cursor: pointer; border-radius: 3px;
}
.meld-toast-x:hover { color: var(--text); }
.meld-toast-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (max-width: 560px) {
  .meld-toasts { left: 1rem; right: 1rem; width: auto; }
}

/* ------------------------------------------------------------------ *
 * THE OVERFLOW SHEET
 *
 * Everything the phone's four-tab bar has no room for. Slides up from the
 * bottom, above the bar, and closes when you tap away from it.
 * ------------------------------------------------------------------ */
.sh-veil {
  position: fixed; inset: 0; z-index: 97;
  background: rgba(0, 0, 0, .55); display: flex; align-items: flex-end;
}
.sh-sheet {
  width: 100%; background: var(--panel); border-top: 1px solid var(--line);
  border-radius: 3px 16px 0 0;
  /* THE SHEET ENDS WHERE ITS CONTENT ENDS.
     The 5rem that used to sit here was clearance for the phone tab bar, on the
     assumption the bar shows through. It does not: the veil is z-index 97 and
     the bar is 92, so the bar is behind the sheet and that 5rem reserved room
     for something nobody can see - 80px of empty panel under the social icons.
     The only real clearance needed is the home indicator, and this is the one
     place that owns it, so it is still correct when the footer fails to clone
     and Sign out is the last row. */
  padding: .6rem .6rem calc(.6rem + env(safe-area-inset-bottom, 0px));
  animation: sh-sheet-in .16s ease-out;
}
@keyframes sh-sheet-in { from { transform: translateY(12px); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .sh-sheet { animation: none; } }
.sh-sheet-row {
  display: flex; align-items: center; gap: .8rem; width: 100%;
  font: inherit; font-size: .95rem; text-align: left; text-decoration: none;
  padding: .85rem .9rem; border-radius: 3px; border: 0;
  background: transparent; color: var(--txt); cursor: pointer;
}
.sh-sheet-row:hover { background: var(--panel-2); }
.sh-sheet-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.sh-sheet-row .sh-ico { width: 20px; height: 20px; flex: 0 0 20px; color: var(--muted); }

/* The footer, copied in from the page. It is laid out here rather than
   inheriting .meld-foot-inner's bar layout, which assumes a full-width strip
   across the bottom of a window and not a row inside a sheet. */
.sh-sheet-foot {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: .5rem 1.1rem;
  width: auto; max-width: 100%; margin: 0;
  padding: .7rem .9rem .2rem;
}
/* The icon rules live under .meld-foot, and this copy is deliberately NOT
   inside one - so without these the anchors collapse to nothing and the row
   renders as Terms and Privacy with an invisible gap where Instagram, TikTok,
   X and the support address should be. An SVG with no width is not a small
   icon, it is no icon. */
.sh-sheet-foot .icons { display: flex; gap: 1.3rem; }
.sh-sheet-foot .icons a {
  display: inline-flex; padding: .4rem; color: var(--txt); opacity: .7;
}
.sh-sheet-foot .icons a:hover { opacity: 1; color: var(--accent); }
.sh-sheet-foot .icons svg { width: 22px; height: 22px; display: block; }
.sh-sheet-foot .meld-foot-links { justify-content: center; }

/* A desktop never sees it: the rail is right there. */
@media (min-width: 721px) { .sh-veil { display: none; } }

/* Three states, not two. An open tab is not a person: "idle" is the page open
   with nobody touching it, and it is the difference between waiting for a
   reply and waiting for nothing. */
.meld-dot-on, .meld-dot-idle, .meld-dot-off {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  flex: 0 0 auto; vertical-align: middle;
}
.meld-dot-on { background: var(--ok); box-shadow: 0 0 0 3px rgba(93, 162, 113, .16); }
.meld-dot-idle { background: #e8a33d; box-shadow: 0 0 0 3px rgba(232, 163, 61, .16); }
.meld-dot-off { background: var(--faint); opacity: .55; }

/* ==================================================================== *
 * THE SIGNED-IN SHELL
 *
 * MOVED HERE FROM public/social/index.html. The rail belonged to one page,
 * so it vanished the moment somebody opened their profile, their messages,
 * or the studio - and the only way back was the browser's back button. A
 * navigation that disappears when you navigate is not navigation.
 *
 * It lives in the shared stylesheet because every signed-in page draws it
 * now; /js/rail.js builds the markup.
 * ==================================================================== */
  /* ------------------------------------------------------------------ *
   * THE SHELL
   *
   * Signing in lands here, not on a settings page, because the first thing
   * anybody wants from a social product is other people's work. The rail is
   * how you get everywhere else, so it is present on every view rather than
   * being a menu you open.
   * ------------------------------------------------------------------ */
  /* ------------------------------------------------------------------ *
   * THE SHELL
   *
   * A collapsible rail down the left, not a row of tabs across the top. The
   * row worked on a desktop and became a sideways scroll on a phone, which is
   * the one gesture nobody discovers: the items past the edge may as well not
   * exist.
   *
   * Collapsed it is icons only and 60px wide; expanded it is 220px with
   * labels. The choice is remembered per browser, because a navigation that
   * resets itself every page load is one you stop trusting.
   * ------------------------------------------------------------------ */
  /* align-self, because a page that makes <body> a centring flex column - the
     jam page does - would otherwise shrink-wrap this grid to its content and
     leave the rail floating in the middle of the window. */
  .sh { width: 100%; align-self: stretch; max-width: none; margin: 0; padding: 0;
        display: grid; gap: 0;
        grid-template-columns: var(--rail, 220px) minmax(0, 1fr);
        align-items: stretch; min-height: calc(100dvh - var(--meld-nav-h, 56px)); }
  .sh.is-tight { --rail: 60px; }
  /* No rail at all: signed out, or a page whose shell has nothing to put in
     it. One column, full width. */
  .sh.is-alone { grid-template-columns: minmax(0, 1fr); }

  /* ------------------------------------------------------------------ *
   * A SIGNED-IN PAGE IS A FRAME, NOT A DOCUMENT
   *
   * "all pages should not be scrollable... the bottom bar with the social
   * link should always be at the bottom, I need to scroll down to see them
   * in mobile."
   *
   * He is right, and the old shape could never satisfy it. The page was a
   * long document with bars stuck onto it: the top nav sticky, the footer
   * fixed on a desktop but UNPINNED on a phone (two fixed bars would have
   * eaten a third of the screen and buried the content under both). So on a
   * phone the social icons and the legal links sat at the end of a document
   * you had to scroll to reach - exactly what he hit.
   *
   * The fix is not another pinned bar. It is to stop the document scrolling
   * at all. The shell is exactly one viewport tall, the bars are ROWS of
   * that frame rather than things floating over it, and the one part that
   * scrolls is the column of content between them. Nothing can be under
   * anything else, because nothing overlaps: every bar owns its own strip.
   *
   * This is how every app on the phone already behaves, and it is why the
   * message thread can finally scroll inside its own box instead of
   * stretching the page out underneath the composer.
   * ------------------------------------------------------------------ */
  body.app-shell {
    /* --meld-vh is the VISUAL viewport: the screen minus the keyboard. See
       trackViewport() in rail.js for why 100dvh is not that, and why the
       difference is the whole app sliding upwards when you type. 100dvh is
       the fallback for a browser with no visualViewport, where it is also the
       right answer. */
    height: var(--meld-vh, 100dvh); max-height: var(--meld-vh, 100dvh);
    overflow: hidden;
    /* Fixed, so there is no page left to scroll even for a moment. A frame
       that can be scrolled at all will be, by the browser, on your behalf,
       at the worst possible time. */
    /* top follows the VISUAL viewport. iOS keeps the layout viewport at full
       height with the keyboard up and offsets the visual one inside it, so a
       frame pinned to 0 sits too high and leaves dead space under the
       composer. --meld-vv-top is 0 everywhere else, so this is inert on
       Android and desktop. */
    position: fixed; inset: var(--meld-vv-top, 0px) 0 auto 0; width: 100%;
    display: flex; flex-direction: column; align-items: stretch;
    /* The document no longer scrolls, so there is nothing to hold clear of
       a pinned footer - the footer is a row now. */
    padding-bottom: 0;
  }
  /* The shell takes whatever is left after the bars. min-height:0 is the
     load-bearing half: without it a flex item refuses to be shorter than its
     content and the frame grows past the window again. */
  body.app-shell > .sh { flex: 1 1 auto; min-height: 0; height: auto; }

  /* THE ONLY SCROLLER ON THE PAGE. */
  body.app-shell .sh-main {
    min-height: 0; overflow-y: auto; overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    /* Reaching the end of the feed must not start dragging the frame. */
    overscroll-behavior: contain;
  }

  /* The rail is a column of the frame. It was sticky because the page
     scrolled underneath it; nothing scrolls underneath it now. */
  body.app-shell .sh-side {
    position: static; top: auto; height: auto; align-self: stretch;
    min-height: 0;
  }

  /* The footer likewise: pinned by the frame, not by itself. */
  body.app-shell .meld-foot {
    position: static; flex: 0 0 auto; margin: 0;
  }


  .sh-side { position: sticky; top: var(--meld-nav-h, 56px); align-self: start;
             height: calc(100dvh - var(--meld-nav-h, 56px));
             display: flex; flex-direction: column; gap: .15rem;
             padding: .8rem .5rem; overflow-y: auto; overflow-x: hidden;
             border-right: 1px solid var(--line); background: #14120f; }

  .sh-toggle { display: flex; align-items: center; gap: .7rem; width: 100%;
               font: inherit; font-size: .8rem; color: var(--faint);
               background: transparent; border: 1px solid transparent;
               border-radius: 3px; padding: .5rem .55rem; cursor: pointer;
               margin: 0 0 .5rem; transition: var(--btn-transition); }
  .sh-toggle:hover { color: var(--text); border-color: var(--line); }
  .sh-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

  .sh-me { padding: .1rem .55rem .8rem; border-bottom: 1px solid var(--line);
           margin: 0 0 .5rem; min-width: 0; }
  .sh-me-name { font-size: .92rem; font-weight: 600; margin: 0;
                white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .sh-me-at { font-size: .76rem; color: var(--faint); margin: .1rem 0 0;
              white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

  .sh-link { display: flex; align-items: center; gap: .7rem; width: 100%;
             font: inherit; font-size: .9rem; text-align: left;
             padding: .55rem .55rem; border-radius: 3px; border: 1px solid transparent;
             background: transparent; color: var(--muted); cursor: pointer;
             text-decoration: none; transition: var(--btn-transition);
             white-space: nowrap; }
  .sh-link:hover { color: var(--text); border-color: var(--line); }
  .sh-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
  .sh-link[aria-current="true"] { color: var(--accent); border-color: var(--line);
                                  background: rgba(232, 163, 61, .07); }
  .sh-ico { width: 18px; height: 18px; flex: 0 0 18px; }
  .sh-label { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }
  .sh-badge { flex: 0 0 auto; font-size: .7rem; min-width: 1.3rem; text-align: center;
              padding: .08rem .32rem; border-radius: 999px;
              background: var(--accent); color: #241f1a; font-weight: 700; }
  .sh-sep { height: 1px; background: var(--line); margin: .5rem .3rem; }

  /* Collapsed: the icon only, centred, with the label kept for screen readers. */
  .sh.is-tight .sh-label,
  .sh.is-tight .sh-me,
  .sh.is-tight .sh-toggle .sh-label { display: none; }
  .sh.is-tight .sh-link { justify-content: center; padding-left: 0; padding-right: 0; }
  .sh.is-tight .sh-toggle { justify-content: center; }
  /* The unread count still has to be visible when there are no words. */
  .sh.is-tight .sh-badge { position: absolute; transform: translate(12px, -12px);
                           font-size: .62rem; min-width: 1rem; padding: 0 .25rem; }
  .sh.is-tight .sh-link { position: relative; }

  /* The SHELL is full bleed - the rail belongs against the edge of the window,
     not floating in a centred column. The CONTENT still reads the shared page
     width, so a feed on a 2560px monitor is a column you can read rather than
     one line of text a metre wide. */
  /* The overflow tab exists only for the phone bar. On a desktop the rail
     already shows everything it would list. */
  .sh-more { display: none; }

  .sh-main { min-width: 0; padding: 1.6rem 1.6rem 3rem; }
  .sh-inner { width: var(--meld-page); max-width: 100%; margin: 0 auto; }
  .sh-h { display: flex; align-items: flex-end; justify-content: space-between;
          gap: 1rem; flex-wrap: wrap; margin: 0 0 1.2rem; }
  .sh-h h1 { font-size: clamp(1.5rem, 4vw, 2.1rem); margin: 0; letter-spacing: -.015em; }
  .sh-h p { color: var(--muted); margin: .35rem 0 0; font-size: .9rem; }

  /* ------------------------------------------------------------------ *
   * ON A PHONE THIS IS A DIFFERENT SHAPE, NOT A NARROWER ONE
   *
   * A rail down the side of a 360px screen is a wall, and the row of tabs it
   * replaced scrolled sideways - the one gesture nobody discovers, so anything
   * past the edge may as well not exist.
   *
   * So on a phone the navigation moves to the bottom, where a thumb already
   * is, and carries FOUR destinations. That is the well-worn range for a tab
   * bar: three to five. Everything else - Studio, Jam, Master - is already in
   * the bar across the top, so the two do not duplicate each other; the top is
   * the products, the bottom is the social app.
   *
   * The site footer un-pins itself here rather than being hidden: two fixed
   * bars would eat 112px of a screen that has about 600, and Terms and Privacy
   * still have to be reachable. It goes back to the end of the page, which is
   * where a footer belongs anyway.
   * ------------------------------------------------------------------ */
  @media (max-width: 720px) {
    .sh { grid-template-columns: minmax(0, 1fr); }
    .sh-main { padding: 1rem 1rem 1.5rem; }

    .sh-side {
      position: fixed; z-index: 92; inset: auto 0 0 0; height: auto;
      flex-direction: row; justify-content: space-around; align-items: stretch;
      gap: 0; padding: .35rem .25rem calc(.35rem + env(safe-area-inset-bottom, 0px));
      border-right: 0; border-top: 1px solid var(--line);
      background: rgba(20, 18, 15, .94);
      -webkit-backdrop-filter: saturate(140%) blur(10px);
      backdrop-filter: saturate(140%) blur(10px);
      overflow: visible;
    }
    /* Only the primary four. The rest live in the top bar or in settings. */
    .sh-side > :not([data-primary]) { display: none; }
    /* Five across: four destinations and the overflow. */
    .sh-more { display: flex; }
    .sh-link { flex-direction: column; gap: .18rem; justify-content: center;
               padding: .35rem .2rem; border: 0; font-size: .66rem; position: relative; }
    .sh-link[aria-current="true"] { background: transparent; color: var(--accent); }
    .sh-label { display: block; flex: 0 0 auto; font-size: .64rem; letter-spacing: .02em; }
    .sh-ico { width: 21px; height: 21px; flex: 0 0 21px; }
    .sh-badge { position: absolute; top: .1rem; left: 50%; transform: translateX(4px);
                font-size: .6rem; min-width: .95rem; padding: 0 .22rem; }

    /* THE PHONE FRAME: content, then the tab bar, then the footer. Three
       rows that always add up to the window, so the bar and the footer are
       on screen from the first paint - no scrolling to find them, and
       nothing hidden underneath them either. The old version un-pinned the
       footer and left it at the end of a long document. */
    body.app-shell > .sh {
      grid-template-columns: minmax(0, 1fr);
      grid-template-rows: minmax(0, 1fr) auto;
    }
    body.app-shell .sh-main { grid-row: 1; grid-column: 1; }
    body.app-shell .sh-side {
      grid-row: 2; grid-column: 1;
      position: static; inset: auto; z-index: auto;
    }
    /* AND ON A PHONE THE FOOTER IS NOT THERE AT ALL.
     *
     * "I think the correct fix is take out the social part for the Mobile
     * view." He is right, and it is the better answer than the one before it.
     * Pinning the footer as a third row did stop it hiding below the fold,
     * but it charged 44px of a 640px screen - permanently, on every page -
     * for two Instagram links and a Terms link. Nobody opens the feed to
     * reach the footer.
     *
     * Nothing becomes unreachable: rail.js copies the footer's own contents
     * into the More sheet, so Terms, Privacy and the social links are one tap
     * away and stay in step with the footer automatically. The desktop, which
     * has the room, keeps it. */
    body.app-shell .meld-foot { display: none; }

    /* WHILE THE KEYBOARD IS UP, THE TAB BAR GOES TOO.
     *
     * Between the keyboard and the top bar there is about half a screen left,
     * and 64px of it was a row of navigation nobody is looking at: you are
     * typing a message, not choosing where to go next. It comes straight back
     * the moment the keyboard closes. This is what the screenshot showed -
     * the bar stranded in the middle of the screen with the conversation
     * squeezed above it. */
    body.app-shell.kb-open .sh-side { display: none; }
  }


/* ==========================================================================
   LIKES AND COMMENTS
   Shared, because a post appears in the feed and on a profile and the two
   were written months apart. One stylesheet so they cannot drift.
   ========================================================================== */

/* A FULL ROW OF ITS OWN. The feed card is itself `display:flex; flex-wrap:
   wrap`, so anything appended into it becomes a flex ITEM and sizes to its
   content - which left the divider above the heart running about a third of
   the way across the card and stopping. flex-basis:100% claims the whole line;
   the shorthand is inert where the host is an ordinary block, so this is safe
   on every surface that mounts it. */
.eng-bar, .eng-comments { flex: 1 0 100%; }
.eng-bar {
  display: flex; align-items: center; gap: .35rem;
  margin-top: .7rem; padding-top: .6rem;
  border-top: 1px solid var(--line, rgba(232,227,217,.08));
}
.eng-btn {
  display: inline-flex; align-items: center; gap: .35rem;
  font: inherit; font-size: .82rem;
  padding: .32rem .55rem; border-radius: 3px;
  border: 1px solid transparent; background: transparent;
  color: var(--txt-faint, rgba(232,227,217,.5));
  cursor: pointer; line-height: 1;
}
/* A span, not a button, when signed out - it is a count, not a control, and
   it must not look pressable. */
span.eng-btn { cursor: default; }
.eng-btn svg { width: 17px; height: 17px; flex: 0 0 auto; }
button.eng-btn:hover { color: var(--txt, #e8e3d9); background: rgba(232,227,217,.05); }
button.eng-btn:focus-visible { outline: 2px solid var(--accent, #6f9fc4); outline-offset: 1px; }
.eng-btn.is-on { color: #c4553d; }
.eng-btn[disabled] { opacity: .55; cursor: default; }
.eng-n { font-variant-numeric: tabular-nums; }

.eng-comments { margin-top: .55rem; display: flex; flex-direction: column; gap: .55rem; }
.eng-list { display: flex; flex-direction: column; gap: .55rem; }
.eng-empty { margin: 0; font-size: .82rem; color: var(--txt-faint, rgba(232,227,217,.45)); }

.eng-c {
  display: flex; flex-direction: column; gap: .2rem;
  padding: .5rem .6rem; border-radius: 3px;
  background: rgba(232,227,217,.03);
}
.eng-c-head { display: flex; align-items: baseline; gap: .5rem; min-width: 0; }
.eng-c-who {
  font-size: .84rem; font-weight: 600; text-decoration: none;
  color: var(--txt, #e8e3d9);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.eng-c-who:hover { color: var(--accent, #6f9fc4); }
.eng-c-when { font-size: .74rem; color: var(--txt-faint, rgba(232,227,217,.4)); flex: 0 0 auto; }
.eng-c-body {
  margin: 0; font-size: .88rem; line-height: 1.45;
  overflow-wrap: anywhere;          /* a pasted URL must not widen the card */
}
.eng-c-foot { display: flex; align-items: center; gap: .2rem; margin-top: .15rem; }
.eng-mini { font-size: .76rem; padding: .22rem .4rem; }
.eng-mini svg { width: 14px; height: 14px; }
.eng-del:hover { color: #c4553d; }

.eng-form { display: flex; gap: .45rem; }
.eng-input {
  flex: 1 1 auto; min-width: 0;      /* shrink rather than push Post off the row */
  font: inherit; font-size: .88rem;
  padding: .45rem .6rem; border-radius: 3px;
  border: 1px solid var(--line, rgba(232,227,217,.12));
  background: var(--field, #1c1a17); color: var(--txt, #e8e3d9);
}
.eng-input:focus { outline: none; border-color: var(--accent, #6f9fc4); }
.eng-send {
  flex: 0 0 auto; font: inherit; font-size: .84rem; font-weight: 600;
  padding: .45rem .8rem; border-radius: 3px;
  border: 1px solid var(--line, rgba(232,227,217,.12));
  background: transparent; color: var(--txt, #e8e3d9); cursor: pointer;
}
.eng-send:hover { border-color: var(--accent, #6f9fc4); color: var(--accent, #6f9fc4); }
.eng-send[disabled] { opacity: .5; cursor: default; }
.eng-note { margin: 0; font-size: .8rem; color: var(--warn-txt); }

/* 16px stops iOS zooming the page when the field takes focus - the same rule
   every other input on the site follows. */
@media (max-width: 600px) {
  .eng-input { font-size: 16px; }
}

/* ==========================================================================
   THE NOTIFICATION BELL
   Injected into the nav by meld-chrome.js, so it exists on every page that
   has the nav and cannot be forgotten on a new one.
   ========================================================================== */

.meld-bell {
  position: relative; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  /* 40px square: a thumb target, not a mouse target. */
  width: 40px; height: 40px;
  border: 1px solid transparent; border-radius: 3px;
  background: transparent; color: var(--txt-faint, rgba(232,227,217,.55));
  cursor: pointer;
}
.meld-bell svg { width: 20px; height: 20px; }
.meld-bell:hover { color: var(--txt, #e8e3d9); background: rgba(232,227,217,.06); }
.meld-bell:focus-visible { outline: 2px solid var(--accent, #6f9fc4); outline-offset: 1px; }
.meld-bell[aria-expanded="true"] { color: var(--txt, #e8e3d9); background: rgba(232,227,217,.08); }

.meld-bell-badge {
  position: absolute; top: 4px; right: 4px;
  min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 3px; background: #c4553d; color: #f4efe4;
  font-size: .66rem; font-weight: 700; line-height: 17px; text-align: center;
  font-variant-numeric: tabular-nums;
}

.meld-bell-panel {
  position: absolute; top: calc(100% + .4rem); right: .8rem; z-index: 60;
  width: min(23rem, calc(100vw - 1.6rem));
  max-height: min(28rem, 70vh); overflow-y: auto;
  padding: .7rem;
  border: 1px solid var(--line, rgba(232,227,217,.12));
  border-radius: 3px;
  background: var(--panel, #14120f);
  box-shadow: 0 14px 40px rgba(0,0,0,.5);
}
.meld-bell-title {
  margin: 0 0 .5rem; font-size: .7rem; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--txt-faint, rgba(232,227,217,.45));
}
.meld-bell-empty { margin: .4rem 0 .3rem; font-size: .86rem; color: var(--txt-faint, rgba(232,227,217,.45)); }
.meld-bell-list { display: flex; flex-direction: column; gap: .3rem; }

.meld-bell-row {
  display: flex; align-items: center; gap: .5rem;
  padding: .5rem .55rem; border-radius: 3px;
}
.meld-bell-row.is-new { background: rgba(111,159,196,.08); }
.meld-bell-main {
  display: flex; flex-direction: column; gap: .1rem;
  flex: 1 1 auto; min-width: 0;      /* shrink, so the buttons never wrap away */
  text-decoration: none; color: inherit;
}
a.meld-bell-main:hover .meld-bell-text { color: var(--accent, #6f9fc4); }
.meld-bell-text {
  font-size: .86rem; color: var(--txt, #e8e3d9); line-height: 1.35;
  overflow-wrap: anywhere;
}
.meld-bell-body {
  font-size: .78rem; color: var(--txt-faint, rgba(232,227,217,.45));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.meld-bell-when { font-size: .72rem; color: var(--txt-faint, rgba(232,227,217,.35)); }

.meld-bell-acts { display: flex; gap: .3rem; flex: 0 0 auto; }
.meld-bell-act {
  font: inherit; font-size: .74rem; font-weight: 600;
  padding: .3rem .5rem; border-radius: 3px;
  border: 1px solid var(--line, rgba(232,227,217,.14));
  background: transparent; color: var(--txt, #e8e3d9); cursor: pointer;
}
.meld-bell-act:hover { border-color: var(--accent, #6f9fc4); color: var(--accent, #6f9fc4); }
.meld-bell-act.is-quiet { color: var(--txt-faint, rgba(232,227,217,.45)); }
.meld-bell-act.is-quiet:hover { border-color: #c4553d; color: #c4553d; }
.meld-bell-act[disabled] { opacity: .5; cursor: default; }

/* The positioning context is the NAV, which is full width and does not
   scroll - not nav-inner, which does both. */
.meld-nav { position: relative; }

/* OUT OF THE NAV'S TYPE RULES.
   The panel is a child of .meld-nav-inner, so `.meld-nav a` was styling every
   line in it - 0.74rem, bold, .16em tracking and UPPERCASE. Notifications came
   out as "FRANKIE SENT YOU A MESSAGE", which is a shout, and the extra
   tracking is what pushed the Ignore button off the edge of the panel.
   Stated rather than inherited, for the same reason the nav states its own
   line-height a few rules above. */
.meld-bell-panel,
.meld-bell-panel a {
  text-transform: none;
  letter-spacing: normal;
  font-weight: 400;
  line-height: 1.4;
}
/* Padding and the underline belong to `.meld-nav a` and must go - but ONLY on
   the anchors. Zeroing padding on the panel too removed its own .7rem inset,
   so every line sat flush against the edge and read as clipped text. */
.meld-bell-panel a { padding: 0; border-bottom: 0; }
.meld-bell-panel a { flex: 1 1 auto; }
.meld-bell-title { font-weight: 700; letter-spacing: .14em; text-transform: uppercase; }
.meld-bell-act { font-weight: 600; }

/* WRAPS RATHER THAN CLIPS. On a phone the text and two buttons do not fit on
   one line, and the buttons are the half that must survive - a notification
   you can read but not answer is the popup this replaced. */
.meld-bell-row { flex-wrap: wrap; }
.meld-bell-acts { margin-left: auto; }

/* ---- a GIF on a comment, and the picker that chose it ---- */

.eng-c-gif {
  max-width: min(100%, 15rem); height: auto;
  border-radius: 3px; margin-top: .3rem; display: block;
}
.eng-gif-btn {
  flex: 0 0 auto; font: inherit; font-size: .72rem; font-weight: 700;
  letter-spacing: .04em;
  padding: .45rem .55rem; border-radius: 3px;
  border: 1px solid var(--line, rgba(232,227,217,.12));
  background: transparent; color: var(--txt-faint, rgba(232,227,217,.5));
  cursor: pointer;
}
.eng-gif-btn:hover { border-color: var(--accent, #6f9fc4); color: var(--accent, #6f9fc4); }

/* The chosen GIF, held until the comment is posted. */
.eng-picked { display: flex; align-items: center; gap: .5rem; }
.eng-picked img { max-height: 68px; width: auto; border-radius: 3px; }
.eng-picked-x {
  font: inherit; font-size: .74rem; padding: .25rem .5rem; border-radius: 3px;
  border: 1px solid var(--line, rgba(232,227,217,.12));
  background: transparent; color: var(--txt-faint, rgba(232,227,217,.45)); cursor: pointer;
}
.eng-picked-x:hover { border-color: #c4553d; color: #c4553d; }

.gp {
  display: flex; flex-direction: column; gap: .5rem;
  padding: .55rem; border-radius: 3px;
  border: 1px solid var(--line, rgba(232,227,217,.12));
  background: rgba(232,227,217,.03);
}
.gp-bar { display: flex; gap: .4rem; }
.gp-search {
  flex: 1 1 auto; min-width: 0; font: inherit; font-size: .86rem;
  padding: .4rem .55rem; border-radius: 3px;
  border: 1px solid var(--line, rgba(232,227,217,.12));
  background: var(--field, #1c1a17); color: var(--txt, #e8e3d9);
}
.gp-close {
  flex: 0 0 auto; font: inherit; font-size: .76rem;
  padding: .4rem .6rem; border-radius: 3px;
  border: 1px solid var(--line, rgba(232,227,217,.12));
  background: transparent; color: var(--txt-faint, rgba(232,227,217,.5)); cursor: pointer;
}
.gp-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: .35rem; max-height: 13rem; overflow-y: auto;
}
.gp-item {
  padding: 0; border: 0; border-radius: 3px; overflow: hidden;
  background: rgba(232,227,217,.04); cursor: pointer; aspect-ratio: 1;
}
.gp-item img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gp-item:focus-visible { outline: 2px solid var(--accent, #6f9fc4); outline-offset: 1px; }
.gp-note { margin: .3rem; font-size: .82rem; color: var(--txt-faint, rgba(232,227,217,.45)); }
/* GIPHY's terms require this wherever their results are shown. Not decoration. */
.gp-mark {
  margin: 0; font-size: .66rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--txt-faint, rgba(232,227,217,.35));
}
@media (max-width: 600px) { .gp-search { font-size: 16px; } }

/* ---- repost, share, plays ---- */
.eng-repost.is-on { color: var(--ok); }
.eng-plays {
  margin-left: auto;                /* pushed to the far end of the bar */
  font-size: .76rem; color: var(--txt-faint, rgba(232,227,217,.4));
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.eng-said {
  flex: 1 0 100%;
  margin: .35rem 0 0; font-size: .78rem;
  color: var(--txt-faint, rgba(232,227,217,.5));
  min-height: 0;                    /* no reserved gap when it says nothing */
}
.eng-said:empty { display: none; }

/* Who reposted it, above the card's own title. */
.fd-reposted, .pf-reposted {
  flex: 1 0 100%;
  margin: 0 0 .3rem; font-size: .78rem;
  color: var(--txt-faint, rgba(232,227,217,.45));
}
.fd-reposted a, .pf-reposted a { color: inherit; text-decoration: none; }
.fd-reposted a:hover, .pf-reposted a:hover { color: var(--accent, #6f9fc4); }

/* ======================================================================== *
 * THE CONSOLE COMPONENT LAYER
 *
 * Three things the whole site now shares, defined once here because they
 * appear on every page and were previously re-invented per page.
 * ======================================================================== */

/* THE MICRO-LABEL. Small, uppercase, mono, widely tracked - the lettering
   silk-screened above a control on a real desk. It sits above panels, above
   sections, and inside the faceplate. There are about forty of them across
   the site and this is the only definition. */
.lbl {
  font-family: var(--font-mono);
  font-size: var(--label-size);
  font-weight: 500;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--faint);
}
.lbl-accent { color: var(--accent); }

/* A PANEL. Recessed, squared, with the fine horizontal grain of painted
   steel. `--panel` is DARKER than `--bg` on purpose: on real hardware the
   recessed areas are the dark ones, and inverting that is most of why a dark
   website looks like a website rather than a device. */
.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  background-image: repeating-linear-gradient(180deg,
    rgba(232,227,217,.022) 0 1px, transparent 1px 3px);
}
.panel-raised { background: var(--panel-2); border-color: var(--line-2); }

/* NUMBERS ARE MONO, ALWAYS. A readout that changes - a meter, a timer, a
   loudness figure - must not reflow as its digits change width. */
.num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* EVERY SLIDER IS AMBER. A bare <input type="range"> is painted in the
   browser's own accent - a bright system blue - which is the one colour on
   this site that belongs to nothing. The master fader in the Studio was
   rendering in it. One rule beats hunting them page by page, and any control
   that genuinely wants another colour can still set accent-color itself. */
input[type="range"] { accent-color: var(--accent); }
/* Checkboxes and radios for the same reason. */
input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); }

/* HEADINGS TAKE THE FACEPLATE FACE.
 *
 * Set here rather than per page, because the h1 on /plans, /master, /studio,
 * /account and the legal pages were each inheriting the prose face and the
 * site had two different heading styles depending on which page you were on.
 *
 * Scoped to the element rather than a class on purpose: every one of these
 * pages writes plain <h1>/<h2>/<h3>, and a class would mean editing twenty
 * files to get one typeface. This file is loaded by all of them.
 *
 * Sizes are NOT set here - each page keeps its own scale. Only the face,
 * weight and the tighter tracking that condensed type needs. */
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -.004em;
  color: var(--txt-bright);
}
/* Condensed type sets small, so headings need a touch more size than the
   prose face did at the same nominal value. */
h1 { font-size: clamp(2.1rem, 4.6vw, 3rem); line-height: 1.04; }

/* A bare <code>, <kbd>, <samp> or <pre> gets the browser's own monospace -
   which on most machines is Courier, and looked exactly like a mistake next to
   IBM Plex Mono everywhere else. The legal pages use <code> for cookie names.
   Found by measuring computed styles in a browser; it is invisible in a diff. */
code, kbd, samp, pre { font-family: var(--font-mono); }

/* A LINK NOTHING ELSE STYLES IS STILL A MELD LINK.
 *
 * A bare <a> takes the browser's own #0000EE, which on warm graphite is the
 * one colour on this site that belongs to nothing - and it is invisible in a
 * diff, because the CSS for it does not exist. Found by reading computed
 * styles across every page: /how had one, and the account page's "see plans"
 * line had another inside a panel.
 *
 * Element selector, so it is the lowest-specificity rule in the file: every
 * nav link, footer link and button-shaped link that sets its own colour still
 * wins. This is a floor, not an override. */
a { color: var(--accent); }
a:hover { color: var(--accent-hot); }
