/* Layout: the shell, the top bar and the camera workspace, for phone
 * portrait, phone landscape, tablet and laptop.
 *
 * The rules that matter most:
 * - phone: stage, result and the main action fit the first screen, and the
 *   fixed parts (top bar, transcript, action bar) take at most about 30% of it;
 *   details live below, reached by scrolling, never between the stage and its
 *   result;
 * - laptop (1366x768 and up): stage, result, transcript and actions fit the
 *   window without scrolling; the side column holds supporting cards only.
 *
 * The legacy layer styles .workspace and .side-panel too, so the properties
 * it sets are reset here explicitly rather than left to chance.
 */

@layer layout {
  .app-shell {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    /* The legacy layer paints a gradient here in the dark theme. */
    background: var(--color-page);
  }

  /* Top bar */
  .topbar {
    position: sticky;
    top: 0;
    z-index: var(--z-topbar);
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--sp-2);
    height: var(--size-topbar);
    min-height: 0;
    padding: 0 var(--sp-3);
    padding-top: env(safe-area-inset-top);
    box-sizing: content-box;
    border-bottom: 1px solid var(--color-line);
    background: var(--color-page);
    backdrop-filter: none;
    flex-wrap: nowrap;
  }
  .topbar .brand__name { display: none; }
  /* The "deneysel" tag only fits beside the tabs on a laptop. */
  .topbar .modes__tag { display: none; }
  .topbar__end { display: flex; align-items: center; gap: var(--sp-1); }
  .topbar__end .live-indicator { display: none; }

  /* Phone: the secondary links live in the "Diğer" popover. */
  .topbar__links.menu {
    inset: auto var(--sp-3) auto auto;
    top: calc(var(--size-topbar) + env(safe-area-inset-top) + var(--sp-1));
    min-width: 14rem;
    flex-direction: column;
    align-items: stretch;
  }
  .topbar__links.menu:popover-open { display: flex; }
  /* Without the Popover API the app opens the menu through data-open, and
     the browser neither hides nor places it, so this does both. */
  .topbar__links.menu[data-open="false"] { display: none; }
  .topbar__links.menu[data-open="true"] {
    position: fixed;
    z-index: var(--z-popover);
    display: flex;
  }
  .topbar__links .navlink { justify-content: flex-start; }

  /* Workspace */
  .app-shell[data-view="app"] .workspace {
    display: block;
    width: auto;
    max-width: none;
    margin: 0;
    padding: 0;
  }

  /* The stage and its result share one grid area, so the result lies over
     the bottom of the stage while staying outside it in the markup. */
  .camera-column {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto;
    grid-template-areas: "stage" "compose";
    /* The top bar's 1 px bottom border is outside its content box. */
    height: calc(100dvh - var(--size-topbar) - 1px - env(safe-area-inset-top));
    min-height: 26rem;
  }
  .camera-column > .stage { grid-area: stage; min-height: 0; }
  .camera-column > .plate { grid-area: stage; align-self: end; margin: var(--sp-3); }
  .camera-column > .compose { grid-area: compose; }

  .compose {
    display: grid;
    /* minmax(0, ...) or a long transcript widens the column past the screen. */
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-3) calc(var(--sp-3) + env(safe-area-inset-bottom));
  }

  .dock {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
    position: static;
  }
  .dock > .btn { flex: 0 0 auto; }
  /* 6rem keeps Sil, Boşluk and Ekle on one row down to 320 px. */
  .dock > .btn--grow { flex: 1 1 6rem; }
  /* The word and coach bars have four labelled actions: two per row. */
  .app-shell:not([data-mode="letter"]) .dock > .btn {
    flex: 1 1 calc(50% - var(--sp-1));
    min-width: 0;
    white-space: normal;
    text-align: center;
  }
  /* Icon first on the phone: the label stays for screen readers. */
  .dock .btn__label--phone-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .dock .kbd { display: none; }

  .side-panel {
    position: static;
    top: auto;
    max-height: none;
    overflow: visible;
    display: grid;
    gap: var(--sp-3);
    padding: var(--sp-3);
    background: transparent;
    border: 0;
    box-shadow: none;
  }

  /* Upright phones and tablets. What the first visit shows follows the
     stage's own height, which already counts the top bar, the transcript
     and the mode's rows of actions: the illustration shrinks, then goes,
     then the facts, the privacy line and the second button, before the
     content would need a scroll. It ends above the message line rather
     than keeping padding for it: once the content is taller than the
     stage, padding no longer keeps the two apart. */
  @media (max-width: 63.99rem) {
    .camera-column > .stage { container: stage / size; }
    .stage__empty { bottom: var(--size-stage-message); padding-bottom: var(--sp-2); }
    /* The problem hides the message line, so it may use the whole stage. */
    .stage__empty:has(> .stage__problem:not([hidden])) { bottom: 0; padding-bottom: var(--sp-6); }
    @container stage (max-height: 42.5rem) {
      .stage__empty { gap: var(--sp-4); padding-top: var(--sp-12); }
      .stage__illustration { width: 72px; }
    }
    @container stage (max-height: 38rem) {
      .stage__illustration { display: none; }
    }
    @container stage (max-height: 32rem) {
      .stage__facts { display: none; }
    }
    @container stage (max-height: 26rem) {
      .stage__lead { display: none; }
    }
    /* A narrow stage wraps the headline and the facts onto more lines. */
    @container stage (max-width: 21rem) and (max-height: 48rem) {
      .stage__illustration { display: none; }
    }
    @container stage (max-width: 21rem) and (max-height: 36rem) {
      .stage__facts { display: none; }
    }
    /* The camera start is the stage's main action; on a stage this short
       "Örneği izleyin" (the camera-free demo) gives way to it. */
    @container stage (max-height: 22rem) {
      .stage__intro .stage__cta > .btn--stage { display: none; }
    }
    @container stage (max-height: 30rem) {
      .stage__problem-icon { display: none; }
      .stage__problem { gap: var(--sp-3); }
    }
    @container stage (max-height: 23rem) {
      .stage__empty:has(> .stage__problem:not([hidden])) { padding-block: var(--sp-12) var(--sp-3); }
      .stage__problem { gap: var(--sp-2); }
      .stage__problem-text { font-size: var(--fs-xs); }
    }
    @container stage (max-height: 20rem) {
      .stage__problem .stage__cta > .btn--stage { display: none; }
    }
    /* A short stage leaves the demo's hand little room between its card and
       the plate, so the card takes the top row itself: the chip gives way
       (the card says what is playing), and the stop keeps only its icon, as
       the coach's close does; its label stays for screen readers. */
    @container stage (max-height: 36rem) {
      .stage[data-demo] .stage-chip { display: none; }
      .stage-demo { flex: 1 1 0; order: 0; min-width: 0; }
      .stage-demo__text { font-size: var(--fs-xs); }
      .stage-demo__stop { width: var(--size-target); min-height: var(--size-target); padding: 0; gap: 0; font-size: 0; }
    }
  }
  /* A short laptop window: the same steps, by the window's height. */
  @media (min-width: 64rem) and (max-height: 46rem) {
    .stage__illustration { display: none; }
  }
  @media (min-width: 64rem) and (max-height: 40rem) {
    .stage__facts { display: none; }
  }
  @media (min-width: 64rem) and (max-height: 36rem) {
    .stage__lead { display: none; }
  }
  /* The narrowest phones: tighter tabs so they stay clear of "Diğer". */
  @media (max-width: 22.5rem) {
    .topbar .modes__item { padding-inline: var(--sp-2); }
  }

  /* Phone landscape: the stage fills the height on the left; the mode switch,
     the result, the transcript and the actions stand in a column on the
     right. There is no top bar: its switch and "Diğer" lie over the column's
     first row, and the brand is left out (the Harf tab does what the brand
     link does). Narrower than a laptop only, so a short desktop window keeps
     the laptop layout instead of a mix of both. */
  @media (orientation: landscape) and (max-height: 32rem) and (max-width: 63.99rem) {
    .app-shell { position: relative; }
    .topbar {
      position: absolute;
      top: 0;
      right: 0;
      left: auto;
      width: var(--size-land-side);
      height: auto;
      box-sizing: border-box;
      grid-template-columns: minmax(0, 1fr) auto;
      padding: max(var(--sp-3), env(safe-area-inset-top)) max(var(--sp-3), env(safe-area-inset-right)) 0 var(--sp-3);
      border-bottom: 0;
      background: transparent;
    }
    .topbar .brand { display: none; }
    .topbar__links.menu {
      top: calc(max(var(--sp-3), env(safe-area-inset-top)) + var(--size-land-switch) + var(--sp-1));
      right: max(var(--sp-3), env(safe-area-inset-right));
    }

    /* Rows: top padding, the switch's slot, the result, the transcript, a
       spring, the actions, bottom padding. The result's row may shrink below
       its content, so the actions always stay in the window. */
    .camera-column {
      height: 100dvh;
      min-height: 0;
      gap: 0;
      grid-template-columns: minmax(0, 1fr) var(--size-land-side);
      grid-template-rows:
        max(var(--sp-3), env(safe-area-inset-top)) var(--size-land-switch) minmax(0, auto)
        auto minmax(0, 1fr) auto max(var(--sp-3), env(safe-area-inset-bottom));
      grid-template-areas: "stage ." "stage ." "stage plate" "stage strip" "stage ." "stage dock" "stage .";
    }
    /* A plain div with no role, so display: contents drops nothing a screen
       reader needs; its two parts become rows of the column. */
    .camera-column > .compose { display: contents; }
    .compose > .strip,
    .compose > .dock,
    .camera-column > .plate {
      margin: var(--sp-2) max(var(--sp-3), env(safe-area-inset-right)) 0 var(--sp-3);
    }
    .compose > .strip { grid-area: strip; min-height: var(--size-land-strip); }
    .compose > .dock {
      grid-area: dock;
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .dock > .btn { min-width: 0; white-space: normal; text-align: center; }
    .app-shell[data-mode="letter"] .dock > .btn--grow { grid-column: 1 / -1; }
    .dock .btn__label--phone-hidden { position: static; width: auto; height: auto; clip-path: none; }

    /* The result is a card on the page, not a plate on the stage, so the
       stage colours it reads point at the page's. The lock colour becomes
       the primary: saffron as a ring or a bar on white would be 1.6:1. */
    .camera-column > .plate {
      grid-area: plate;
      align-self: stretch;
      justify-self: stretch;
      min-height: 0;
      overflow: hidden;
      --stage-plate: var(--color-surface);
      --stage-text: var(--color-text);
      --stage-text-2: var(--color-text-2);
      --stage-bar-off: var(--color-control);
      --stage-lock: var(--color-primary);
      justify-content: flex-start;
      gap: var(--sp-3);
      /* One pixel of padding gives way to the locked border's second one, so
         locking does not move the content. */
      padding: calc(var(--sp-3) + 1px);
      border: 1px solid var(--color-line);
      background: var(--color-surface);
    }
    .stage[data-state="good"] + .plate { padding: var(--sp-3); border: 2px solid var(--color-primary); }
    /* Beside the stage the card has the room to show that it is waiting:
       the ring and the level word, without an empty meter. */
    .stage:has(> .stage__empty:not([hidden])) + .plate .plate__visual { display: grid; }
    .stage:has(> .stage__empty:not([hidden])) + .plate .plate__level { display: flex; }
    .stage:has(> .stage__empty:not([hidden])) + .plate :is(.signal, .plate__pct) { display: none; }
    .stage:has(> .stage__empty:not([hidden])) + .plate .plate__message { text-align: start; }
    /* Beside the ring there are 110 to 160 px: the level word on its own
       line, the meter and percent under it, then two lines of message. That
       keeps the card about the ring's height, so the column fits every tier;
       a longer message is cut off on screen, not in the DOM. */
    .camera-column > .plate .plate__level { line-height: 1.25; }
    .stage:not([data-kind="word"]) + .plate .plate__decision { flex-basis: 100%; }
    .camera-column > .plate .plate__message {
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 2;
      line-clamp: 2;
      overflow: hidden;
    }
    /* A word stands above one row of level and a line of message. */
    .stage[data-kind="word"] + .plate { row-gap: var(--sp-1); }
    .stage[data-kind="word"] + .plate .plate__message { -webkit-line-clamp: 1; line-clamp: 1; }
    /* The word and coach actions have long labels in a 120 px half. */
    .app-shell:not([data-mode="letter"]) .dock > .btn {
      padding-inline: var(--sp-2);
      font-size: var(--fs-sm);
      line-height: var(--lh-tight);
    }
    /* Three tabs and "Diğer" in a 264 px column. */
    .topbar .modes__item { padding-inline: var(--sp-2); }

    /* The stage. Its top row clears a notch on the left. */
    .camera-column > .stage { container: stage / inline-size; }
    .stage__top { inset: var(--sp-3) var(--sp-3) auto max(var(--sp-3), env(safe-area-inset-left)); }
    /* The stage is short here: the demo's card shares the top row with the
       chip, and the stop keeps only its icon; on the narrowest stage the
       chip gives way, as on a short upright phone. */
    .stage-demo { flex: 1 1 0; order: 0; min-width: 0; }
    .stage-demo__text { font-size: var(--fs-xs); }
    .stage-demo__stop { width: var(--size-target); min-height: var(--size-target); padding: 0; gap: 0; font-size: 0; }
    @container stage (max-width: 23.75rem) {
      .stage[data-demo] .stage-chip { display: none; }
    }
    .stage__empty {
      /* The top clears the chip; the plate is beside the stage, so the
         bottom keeps no room for it. */
      bottom: 0;
      padding: var(--size-stage-clear) var(--sp-6) var(--sp-6) max(var(--sp-6), env(safe-area-inset-left));
      gap: var(--sp-3);
    }
    .stage__illustration, .stage__facts { display: none; }
    .stage__lead { display: block; }
    .stage__cta { flex-direction: row; }
    @container stage (max-width: 23.75rem) {
      .stage__headline { font-size: var(--fs-xl); }
      .stage__lead { display: none; }
      .stage__cta { flex-direction: column; }
    }
    @container stage (max-width: 17.5rem) {
      /* "Örneği izleyin" gives way to the camera start. */
      .stage__intro .stage__cta > .btn--stage { display: none; }
    }

    /* The camera problem, without its icon (the stage is under 40rem high). */
    .stage__empty:has(> .stage__problem:not([hidden])) { padding-block: var(--size-stage-clear) var(--sp-4); }
    .stage__problem { gap: var(--sp-3); }
    @container stage (max-width: 23.75rem) {
      .stage__problem { gap: var(--sp-2); }
      .stage__problem-title { font-size: var(--fs-lg); }
      .stage__problem-text { font-size: var(--fs-xs); }
    }

    /* The shortest tier (568x320): the letter actions in one row, Sil and
       Boşluk as icons (their labels stay for screen readers), a word without
       its message line, and only the problem's main action. */
    @media (max-height: 21.25rem) {
      .topbar .modes { padding: calc(var(--sp-1) / 2); }
      .stage[data-kind="word"] + .plate .plate__message { display: none; }
      .app-shell[data-mode="letter"] .compose > .dock { grid-template-columns: auto auto minmax(0, 1fr); }
      .app-shell[data-mode="letter"] .dock > .btn--grow { grid-column: auto; }
      .app-shell[data-mode="letter"] .dock > .btn:not(.btn--grow) { width: var(--size-control); padding: 0; }
      .app-shell[data-mode="letter"] .dock .btn:not(.btn--grow) :is(.btn__label, .btn__label--phone-hidden) {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
      }
      @container stage (max-width: 23.75rem) {
        .stage__problem .stage__cta > .btn--stage { display: none; }
      }
    }
  }

  /* Laptop */
  @media (min-width: 64rem) {
    .topbar {
      grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
      gap: var(--sp-4);
      padding-inline: var(--sp-6);
    }
    .topbar .brand__name { display: inline; }
    .topbar .modes__tag { display: inline; }
    .app-shell[data-mode="word"] .stage__illustration { display: block; }
    .topbar .brand__mark { width: 32px; height: 32px; }
    .topbar__modes { justify-self: center; }
    .topbar__modes .modes__item { flex: none; min-height: 40px; padding-inline: 22px; }
    .topbar__end { justify-self: end; }
    .topbar__end .live-indicator.is-live { display: inline-flex; }
    .topbar__more { display: none; }

    /* The popover becomes a plain row of links. No :popover-open in this
       list: a browser that does not know the pseudo-class drops the whole
       rule, and the laptop links would be unstyled there. The fallback's
       data-open states are listed so they cannot hide or float the row. */
    .topbar__links.menu,
    .topbar__links.menu[data-open] {
      position: static;
      inset: auto;
      display: flex;
      flex-direction: row;
      align-items: center;
      gap: var(--sp-1);
      min-width: 0;
      margin: 0;
      padding: 0;
      overflow: visible;
      border: 0;
      background: transparent;
      box-shadow: none;
    }
    .topbar__links .navlink { min-height: 40px; }
    .topbar__links .navlink--icon { width: 40px; padding: 0; justify-content: center; }
    .topbar__links .navlink--icon .navlink__label {
      position: absolute;
      width: 1px;
      height: 1px;
      overflow: hidden;
      clip-path: inset(50%);
      white-space: nowrap;
    }

    .app-shell[data-view="app"] .workspace {
      display: grid;
      grid-template-columns: minmax(0, 1fr) var(--size-side);
      grid-template-rows: minmax(0, 1fr);
      align-items: stretch;
      gap: var(--sp-4);
      height: calc(100dvh - var(--size-topbar) - 1px);
      padding: var(--sp-4) var(--sp-6) var(--sp-6);
      box-sizing: border-box;
    }
    .camera-column { height: auto; min-height: 0; gap: var(--sp-3); }
    .compose {
      grid-template-columns: minmax(0, 1fr) auto;
      align-items: center;
      gap: var(--sp-2);
      padding: 0;
    }
    .compose .strip { min-height: 60px; }
    .dock { flex-wrap: nowrap; }
    .dock > .btn--grow { flex: none; }
    .dock .btn__label--phone-hidden { position: static; width: auto; height: auto; overflow: visible; clip-path: none; }
    .dock .kbd { display: inline-flex; }

    .side-panel {
      min-height: 0;
      overflow: auto;
      align-content: start;
      padding: 0;
    }

    /* The plate sits bottom-left, as wide as its content and at most 22rem:
       with a 112 px ring it covers part of a raised hand in about 2 to 7 of
       100 frames, against 8 to 21 at the 148 px ring. When the hand stays
       under it anyway, plate-side.js sends it to the bottom-right, which the
       column, a size container, measures for the slide. */
    .camera-column { container: column / inline-size; }
    .camera-column > .plate {
      justify-self: start;
      margin: var(--sp-4);
      max-width: min(22rem, calc(100% - 2 * var(--sp-4)));
      padding: var(--sp-3) var(--sp-5) var(--sp-3) var(--sp-3);
      gap: var(--sp-4);
      transition: translate var(--dur-2) var(--ease-out);
    }
    .stage[data-plate-side="end"] + .plate { translate: calc(100cqw - 100% - 2 * var(--sp-4)) 0; }
    .stage__top { inset: var(--sp-4) var(--sp-4) auto; }
    /* The demo's card in the top row, centred over the hand it explains. */
    .stage-demo { flex: 0 1 34rem; order: 0; max-width: none; margin-inline: auto; }
    .stage-demo__stop { margin-inline-start: 0; }
    /* The toast sits just above the transcript row, opposite the plate, so
       it changes corner with it. */
    .toast { inset: auto var(--sp-4) var(--sp-4) auto; margin: 0; }
    .stage[data-plate-side="end"] .toast { inset: auto auto var(--sp-4) var(--sp-4); }
    /* Camera off: the plate is only the message line, centred under the
       empty state. */
    .stage:has(> .stage__empty:not([hidden])) + .plate { justify-self: stretch; max-width: none; }

    /* Empty state: two lines of headline, buttons side by side. */
    .stage__headline { max-width: 26ch; }
    .stage__cta { flex-direction: row; justify-content: center; width: auto; }
    .stage__cta .btn { width: auto; min-width: 11rem; }
    .stage__empty { gap: var(--sp-4); padding-top: var(--sp-12); }
  }

  @media (min-width: 90rem) {
    :root { --size-side: 380px; }
    .topbar { padding-inline: var(--sp-8); }
    .app-shell[data-view="app"] .workspace { padding-inline: var(--sp-8); }
  }
}

@layer utilities {
  /* Mode visibility. Hide-only on purpose: revealing the current mode's
     parts with display: revert !important would override every component's
     own display (a flex card becomes a block). Hiding the other modes' parts
     leaves each component's layout to the component. */
  .app-shell[data-mode="letter"] .mode-only:not(.letter-only),
  .app-shell[data-mode="coach"] .mode-only:not(.coach-only),
  .app-shell[data-mode="word"] .mode-only:not(.word-only) {
    display: none !important;
  }

  .visually-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    margin: -1px !important;
    padding: 0 !important;
    overflow: hidden !important;
    clip-path: inset(50%) !important;
    white-space: nowrap !important;
    border: 0 !important;
  }
}
